Cómo admitir múltiples versiones de Scala en una biblioteca
maven maven-plugin (3)
He hecho algo similar a esto con SBT como ejemplo: https://github.com/seanparsons/scalaz/commit/21298eb4af80f107181bfd09eaaa51c9b56bdc28
Es posible gracias a SBT, lo que permite que todas las configuraciones se determinen en función de otras configuraciones, lo que significa que la mayoría de las otras cosas "deberían funcionar".
En cuanto al aspecto pom.xml, solo puedo recomendar hacer la pregunta en la lista de correo de SBT, pero me sorprendería que no pudieras hacer eso.
Tengo un proyecto de Scala bastante normal que se está construyendo actualmente con Maven. Me gustaría admitir tanto Scala 2.9.x como el próximo 2.10, que no es binario ni compatible con la fuente. Estoy dispuesto a entretener la conversión a SBT si es necesario, pero me he encontrado con algunos desafíos.
Mis requisitos para este proyecto son:
Árbol de fuente única (sin ramificación). Creo que tratar de admitir múltiples ramas simultáneas "maestras" para cada versión de Scala será la forma más rápida de perder las correcciones de errores entre las ramas.
Directorios de origen específicos de la versión. Como las versiones de Scala no son compatibles con el origen, necesito poder especificar un directorio de origen auxiliar para las fuentes específicas de la versión.
Frascos fuente específicos de la versión. Los usuarios finales deberían poder descargar el jar fuente correcto, con las fuentes específicas de la versión correcta, para su versión de Scala para la integración IDE.
Despliegue integrado. Actualmente uso el complemento de lanzamiento de Maven para implementar nuevas versiones en el repositorio Sonatype OSS, y me gustaría tener un flujo de trabajo similarmente simple para las versiones.
Soporte Maven para el usuario final. Mis usuarios finales a menudo son usuarios de Maven, por lo que un POM funcional que refleje con precisión las dependencias es fundamental.
Soporte de jarra sombreada. Necesito poder producir un JAR que incluya un subconjunto de mis dependencias y elimine las dependencias sombreadas del POM publicado.
Cosas que he intentado:
Perfiles de Maven. Creé un conjunto de perfiles de Maven para controlar qué versión de Scala se usa para compilar, usando el complemento Maven build-helper para seleccionar el árbol de fuentes específico de la versión. Esto estaba funcionando bien hasta que llegó el momento de publicar;
Usar clasificadores para calificar versiones no funciona bien, porque los jar de origen también necesitarían clasificadores personalizados (''source-2.9.2'', etc.), y la mayoría de las herramientas IDE no sabrían cómo ubicarlas.
Intenté usar una propiedad de Maven para agregar el sufijo SBT-style _ $ {scala.version} al nombre del artefacto, pero a Maven no le gustan las propiedades en el nombre del artefacto.
SBT. Esto funciona bien una vez que puedes asimilarlo (no es una tarea pequeña a pesar de la extensa documentación). El inconveniente es que no parece haber un equivalente al plugin de colores Maven. He visto:
Proguard. El complemento no se actualiza para SBT 0.12.x, y no se compilará desde el origen porque depende de otro complemento SBT que haya cambiado groupIds, y no tiene una versión 0.12.x bajo el nombre anterior. Todavía no he podido descifrar cómo ordenar a SBT que ignore / reemplace la dependencia del complemento.
OneJar. Esto utiliza la carga de clases personalizada para ejecutar las clases principales de los jar incrustados, que no es el resultado deseado; Quiero que los archivos de clase de mi proyecto estén en el contenedor junto con los archivos de clase (posiblemente renombrados) de mis dependencias sombreadas.
SBT Assembly plugin. Esto puede funcionar hasta cierto punto, pero el archivo POM parece incluir las dependencias que trato de sombrear, lo que no ayuda a mis usuarios finales.
Acepto que puede que no haya una solución que haga lo que quiero para Scala, y / o que necesite escribir mis propios complementos de Maven o Scala para lograr el objetivo. Pero si puedo, me gustaría encontrar una solución existente.
Actualizar
Estoy cerca de aceptar la excelente answer @ Jon-Ander, pero todavía hay una pieza excepcional para mí, que es un proceso de lanzamiento unificado. El estado actual de mi build.sbt está en GitHub . (Lo reproduciré aquí en una respuesta posterior para la posteridad).
El complemento sbt-release no es compatible con compilaciones de varias versiones (es decir, la + release
no se comporta como a uno le gustaría), lo que tiene cierto sentido, ya que el proceso de etiquetado de lanzamiento no tiene por qué suceder en todas las versiones. Pero me gustaría que dos partes del proceso sean de varias versiones: pruebas y publicación.
Lo que me gustaría que sucediera es algo parecido al proceso de creación de maven-release-plugin de dos etapas. La primera etapa haría el trabajo administrativo de actualizar Git y ejecutar las pruebas, lo que en este caso significaría ejecutar + test
para que todas las versiones sean probadas, etiquetadas, actualizadas a una instantánea, y luego empujar el resultado a la corriente ascendente.
La segunda etapa verificaría la versión etiquetada y + publish
, que volverá a ejecutar las pruebas y empujará las versiones etiquetadas al repositorio de Sonatype.
Sospecho que podría escribir los valores de releaseProcess
que hacen cada uno de estos, pero no estoy seguro si puedo admitir múltiples valores de releaseProcess
en mi build.sbt
. Probablemente pueda funcionar con algunos alcances adicionales, pero esa parte de SBT sigue siendo extraña para mí.
Lo que he hecho actualmente es cambiar el releaseProcess
de releaseProcess
para no publicar. Luego tengo que verificar la versión etiquetada a mano y ejecutar + publish
después del hecho, que está cerca de lo que quiero pero compromete, especialmente porque las pruebas solo se ejecutan en la versión scala actual en el proceso de lanzamiento. Podría vivir con un proceso que no es de dos etapas, como el plugin maven, pero implementa una prueba y publicación de varias versiones.
Cualquier comentario adicional que pueda llevarme a través de la última milla será apreciado.
La mayoría de esto está bien soportado en sbt dentro de un único árbol fuente
Los directorios de origen específicos de la versión generalmente no son necesarios. Los programas de Scala tienden a ser compatibles con las fuentes; con frecuencia, de hecho, la construcción cruzada ( http://www.scala-sbt.org/release/docs/Detailed-Topics/Cross-Build ) tiene soporte de primera clase en sbt.
Si realmente necesita un código específico para la versión, puede agregar carpetas fuente adicionales. Poner esto en su archivo build.sbt agregará "src / main / scala- [scalaVersion]" como un directorio de origen para cada versión a medida que realiza una construcción cruzada además del "src / main / scala" regular. (También hay un complemento disponible para generar cuñas entre versiones, pero no lo he probado - https://github.com/sbt/sbt-scalashim )
unmanagedSourceDirectories in Compile <+= (sourceDirectory in Compile, scalaVersion){ (s,v) => s / ("scala-"+v) }
versiones específicas de los archivos fuente: vea la construcción cruzada, funciona de la caja
implementación integrada - https://github.com/sbt/sbt-release (también tiene una increíble integración git)
Usuarios finales de Maven: http://www.scala-sbt.org/release/docs/Detailed-Topics/Publishing.html
Sombreado: he usado este https://github.com/sbt/sbt-assembly que funcionó bien para mis necesidades. Su problema con el complemento de ensamblaje puede resolverse reescribiendo el pom generado. Aquí hay un ejemplo arrancando 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
}
})
}
Complete build.sbt para referencia
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
}
})
}
Mi publicación en el blog http://www.day-to-day-stuff.blogspot.nl/2013/04/fixing-code-and-binary.html contiene un ejemplo de una solución ligeramente más detallada para adjuntar diferentes directorios fuente; uno por mayor S. También explica cómo crear un código específico de la versión de scala que puede ser usado por un código no específico.
Actualización del 2016-11-08 : Sbt ahora es compatible con esto: http://www.scala-sbt.org/0.13/docs/sbt-0.13-Tech-Previews.html#Cross-version+support+for+Scala+sources