Как поддерживать несколько версий Scala в библиотеке
У меня довольно нормальный Scala project, который в настоящее время строится с использованием Maven. Я хотел бы поддержать как Scala 2.9.x, так и предстоящий 2.10, который не является бинарным или исходным. Я готов принять участие в конвертации в SBT, если это необходимо, но я столкнулся с некоторыми проблемами.
Мои требования для этого проекта:
-
Дерево с одним источником (без ветвления). Я считаю, что попытка поддержки нескольких параллельных "главных" ветвей для каждой версии Scala будет самым быстрым способом пропустить исправления между ветвями.
-
Исходные каталоги, зависящие от версии. Поскольку версии Scala не являются совместимыми с исходными кодами, мне нужно указать каталог вспомогательных источников для источников, зависящих от версии.
-
Конкретные исходные банки. Конечные пользователи должны иметь возможность загружать правильную исходную банку с соответствующими исходными версиями для своей версии Scala для интеграции IDE.
-
Интегрированное развертывание. В настоящее время я использую плагин релиза Maven для развертывания новых версий в репозитарии Sonatype OSS и хотел бы иметь аналогичный простой рабочий процесс для выпусков.
-
Поддержка конечных пользователей Maven. Мои конечные пользователи часто являются пользователями Maven, и поэтому функциональный POM, который точно отражает зависимости, является критическим.
-
Поддержка заштрихованной банки. Я должен иметь возможность создавать JAR, который включает подмножество моих зависимостей и удаляет затененные зависимости из опубликованного POM.
Вещи, которые я пробовал:
-
Профили Maven. Я создал набор профилей Maven для управления тем, какая версия Scala используется для сборки, используя плагин Maven build-helper для выбора дерева исходных версий. Это работало хорошо, пока не пришло время публиковать;
-
Использование классификаторов для квалификации версий не работает, потому что исходным банкам также нужны специальные классификаторы ( "источник-2.9.2" и т.д.), и большинство инструментов IDE не будут знать, как найти их.
-
Я попытался использовать свойство Maven, чтобы добавить суффикс _ ${ scala.version} SBT в имя артефакта, но Maven не любит свойства в имени артефакта.
- SBT
. Это хорошо работает, как только вы можете это понять (небольшая задача, несмотря на обширную документацию). Недостатком является то, что, похоже, не похоже на плагин Maven shadow. Я посмотрел:
-
Proguard. Плагин не обновляется для SBT 0.12.x и не будет строиться из источника, потому что он зависит от другого плагина SBT, который изменил groupIds, и не имеет версии 0.12.x под старым именем. Мне еще не удалось выяснить, как проинструктировать SBT игнорировать/заменять зависимость плагина.
-
OneJar. Это использует пользовательскую загрузку классов для запуска основных классов из встроенных банок, что не является желаемым результатом; Я хочу, чтобы файлы классов моего проекта были в банке вместе с (возможно, переименованными) файлами классов из моих затененных зависимостей.
-
Плагин сборки SBT. Это может работать в определенной степени, но в файле POM отображаются зависимости, которые я пытаюсь затенять, что не помогает моим конечным пользователям.
Я согласен с тем, что не может быть решения, которое делает то, что я хочу для Scala, и/или мне может понадобиться написать мои собственные Maven или плагины w60 для достижения цели. Но если я могу найти существующее решение.
Update
Я близок к тому, чтобы принять @Jon-Ander отличный ответ, но для меня есть еще одна выдающаяся штука, которая является единым процессом выпуска. Текущее состояние моего build.sbt находится в GitHub. (Я воспроизведу его здесь в ответ позже для потомков).
Плагин sbt-release не поддерживает сборку с несколькими версиями (т.е. + release
не ведет себя так, как хотелось бы), что делает определенный смысл, поскольку процесс тегирования релиза действительно не обязательно версии. Но я хотел бы, чтобы две части процесса были мульти-версией: тестирование и публикация.
То, что я хотел бы иметь, это нечто похожее на двухэтапный процесс maven-release-плагина. На первом этапе будет выполняться административная работа по обновлению Git и запуску тестов, что в данном случае означает запуск + test
, чтобы все версии были протестированы, помечены, обновлены до моментального снимка, а затем нажали результат вверх по течению.
Второй этап будет проверять тегированную версию и + publish
, которая перезапустит тесты и выведет тегированные версии в репозиторий Sonatype.
Я подозреваю, что могу написать releaseProcess
значения, которые делают каждый из них, но я не уверен, могу ли я поддерживать несколько значений releaseProcess
в моем build.sbt
. Вероятно, он может работать с некоторыми дополнительными областями, но эта часть SBT по-прежнему остается странной для меня.
В настоящее время я изменил releaseProcess
, чтобы не публиковать. Затем мне нужно проверить версию с меткой вручную и запустить + publish
после того, как факт, близкий к тому, что я хочу, но выполняю компромисс, тем более, что тесты выполняются только в текущей версии Scala в процессе выпуска. Я мог бы жить с процессом, который не является двухступенчатым, как плагин maven, но реализует проверку и публикацию нескольких версий.
Любая дополнительная обратная связь, которая может получить меня через последнюю милю, будет оценена.
Ответы
Ответ 1
Большинство из них хорошо поддерживается в sbt в одном дереве исходных текстов
Исходные каталоги, зависящие от версии, обычно не нужны. Scala программы имеют тенденцию быть совместимыми с исходным кодом - так часто на самом деле
crossbuilding (http://www.scala-sbt.org/release/docs/Detailed-Topics/Cross-Build) имеет поддержку первого класса в sbt.
Если вам действительно нужен код версии, вы можете добавить дополнительные исходные папки.
Поместив это в ваш файл build.sbt, вы добавите "src/main/scala - [scalaVersion]" в качестве исходного каталога для каждой версии, поскольку вы перекрестно построили в дополнение к регулярному "src/main/scala".
(есть также плагин для создания прокладок между версиями, но я не пробовал - https://github.com/sbt/sbt-scalashim)
unmanagedSourceDirectories in Compile <+= (sourceDirectory in Compile, scalaVersion){ (s,v) => s / ("scala-"+v) }
версии конкретных исходных банок - см. перекрестное построение, работает из коробки
интегрированное развертывание - https://github.com/sbt/sbt-release (также имеет удивительную интеграцию git)
Конечные пользователи Maven - http://www.scala-sbt.org/release/docs/Detailed-Topics/Publishing.html
Затененный - я использовал этот https://github.com/sbt/sbt-assembly, который отлично работал для моих нужд.
Ваша проблема с плагином сборки может быть решена путем перезаписи созданного pom.
Вот пример, с помощью которого можно вырвать joda-time.
pomPostProcess := {
import xml.transform._
new RuleTransformer(new RewriteRule{
override def transform(node:xml.Node) = {
if((node \ "groupId").text == "joda-time") xml.NodeSeq.Empty else node
}
})
}
Завершить build.sbt для справки
scalaVersion := "2.9.2"
crossScalaVersions := Seq("2.9.2", "2.10.0-RC5")
unmanagedSourceDirectories in Compile <+= (sourceDirectory in Compile, scalaVersion){ (s,v) => s / ("scala-"+v) }
libraryDependencies += "joda-time" % "joda-time" % "1.6.2"
libraryDependencies += "org.mindrot" % "jbcrypt" % "0.3m"
pomPostProcess := {
import xml.transform._
new RuleTransformer(new RewriteRule{
override def transform(node:xml.Node) = {
if((node \ "groupId").text == "joda-time") xml.NodeSeq.Empty else node
}
})
}
Ответ 2
Я сделал что-то похожее на это с SBT в качестве примера:
https://github.com/seanparsons/scalaz/commit/21298eb4af80f107181bfd09eaaa51c9b56bdc28
Это стало возможным благодаря SBT, позволяющему определять все параметры на основе других параметров, что означает, что большинство других вещей должно "просто работать".
Что касается аспекта pom.xml, я могу только порекомендовать вопрос в списке рассылки SBT, я был бы удивлен, если бы вы не могли этого сделать.
Ответ 3
Мой пост в блоге http://www.day-to-day-stuff.blogspot.nl/2013/04/fixing-code-and-binary.html содержит пример немного более тонкого решения для прикрепления разных исходных каталогов; один на майор S. Также он объясняет, как создать scala -версионный код, который может использоваться неспецифическим кодом.
Обновление 2016-11-08: Sbt теперь поддерживает это из коробки: http://www.scala-sbt.org/0.13/docs/sbt-0.13-Tech-Previews.html#Cross-version+support+for+Scala+sources