37 votes

Comment prendre en charge plusieurs versions de Scala dans une bibliothèque

J'ai un assez normal Scala projet actuellement en cours de construction à l'aide de Maven. Je tiens à soutenir à la fois la Scala 2.9.x et le prochain 2.10, ce qui n'est pas binaire ou source compatible. Je suis disposé à recevoir la conversion de SBT, si nécessaire, mais j'ai couru dans un certain nombre de défis.

Mes besoins pour ce projet sont:

  • Arbre source (pas de branchement). Je crois que le fait d'essayer à l'appui simultané de plusieurs "maître" branches pour chaque Scala version sera la façon la plus rapide de miss corrections de bugs entre les branches.

  • Version spécifique répertoires source. Depuis la Scala versions ne sont pas source de compatibile, j'ai besoin d'être capable de spécifier une source auxiliaire d'annuaire pour la version des sources spécifiques.

  • Version spécifique de la source de pots. Les utilisateurs finaux doivent être en mesure de télécharger la source correcte pot, avec la version correcte de sources spécifiques, pour leur version de Scala pour de l'IDE de l'intégration.

  • Intégrée de déploiement. J'utilise actuellement la version plugin Maven pour déployer de nouvelles versions de la Sonatype OSS référentiel, et voudrais avoir un même flux de travail simple pour les rejets.

  • L'utilisateur final Maven soutien. Mes utilisateurs finaux sont souvent Maven utilisateurs, et donc une fonctionnelle de la POM qui reflète fidèlement les dépendances est critique.

  • Ombragée pot de soutien. J'ai besoin d'être en mesure de produire un BOCAL qui contient un sous-ensemble de mes dependenices et supprime le ombragée de dépendances à partir de la publication de POM.

Choses que j'ai essayé:

  • Des profils Maven. J'ai créé un ensemble de profils Maven pour contrôler la version de Scala est utilisé pour construire, à l'aide de l'Maven build-helper plugin pour sélectionner la version spécifique de l'arbre source. Cela fonctionnait bien jusqu'à ce qu'il est venu le temps de publier;

    • En utilisant des classificateurs pour qualifier les versions ne fonctionne pas bien, parce que la source des pots auraient également besoin d'un custom classificateurs (source-2.9.2', etc.), et la plupart des outils IDE ne sais pas comment les localiser.

    • J'ai essayé d'utiliser une propriété Maven pour ajouter le SBT-style _${scala.version} suffixe au nom d'artefact, mais Maven n'aime pas les propriétés de l'artefact nom.

  • SBT. Cela fonctionne bien une fois que vous pouvez grok elle (pas d'une mince tâche, malgré une documentation complète). L'inconvénient est qu'il ne semble pas être un équivalent à l'Maven ombre plugin. J'ai regardé:

    • Proguard. Le plugin n'est pas mis à jour pour SBT 0.12.x, et de ne pas créer à partir de la source, car il dépend d'un autre SBT plugin qui a changé groupIds, et qui n'a pas de 0,12.x version sous l'ancien nom. Je n'ai pas encore été en mesure de travailler sur la façon d'instruire SBT ignorer/remplacer le plugin de dépendance.

    • OneJar. On utilise à cette classe personnalisée de chargement pour exécuter les Principales classes intégrées pots, ce qui n'est pas le résultat souhaité; je veux la catégorie fichiers de mon projet d'être dans le pot avec (éventuellement renommé) de fichiers de classe de mon ombré dépendances.

    • SBT Assemblée plugin. Cela peut fonctionner à un certain degré, mais le fichier POM semble inclure les dépendances que je suis en train de l'ombre, ce qui n'aide pas à mes utilisateurs finaux.

J'accepte qu'il ne peut pas être une solution qui répond à ce que je veux pour Scala, et/ou j'ai peut-être besoin d'écrire mon propre Maven ou Scala plugins pour atteindre l'objectif. Mais si je peux, j'aimerais trouver une solution existante.

Mise à jour

Je suis près à accepter @Jon-Ander excellente réponse, mais il y a encore une pièce exceptionnelle pour moi, ce qui est unifié processus de libération. L'état actuel de mon build.sbt est sur GitHub. (Je vais reproduire ici dans une réponse plus tard pour la postérité).

Le sbt-version plugin ne gère pas le multi-version s'appuie (c'est à dire, + release ne se comportent pas comme on le souhaiterait), qui fait une sorte de sentiment que le processus de libération de marquage n'a pas vraiment besoin de passer à travers les versions. Mais je voudrais deux parties du processus multi-version: tests et de l'édition.

Ce que j'aimerais y arriver, c'est quelque chose qui s'apparente à deux étages-maven-release-plugin processus. La première étape serait de faire le travail administratif de la mise à jour de Git et de lancer les tests, qui dans ce cas signifie l'exécution de + test alors que toutes les versions sont testées, l'étiquetage, la mise à jour de l'instantané, et puis en poussant le résultat en amont.

La seconde étape serait de caisse marqués version et + publish, ce qui permettra de relancer les tests et pousser les versions marqués jusqu'à la Sonatype référentiel.

Je soupçonne que j'ai pu écrire, releaseProcess des valeurs de chacun de ces domaines, mais je ne sais pas si je peut prendre en charge plusieurs releaseProcess valeurs dans mon build.sbt. Il ne peut probablement fonctionner avec certains des étendues supplémentaires, mais cette partie de SBT est toujours étrange majick pour moi.

Ce que j'ai actuellement fait que l'on change releaseProcess de ne pas publier. J'ai ensuite à la caisse de la tagged version à la main et exécutez + publish après le fait, qui est proche de ce que je veux, mais ne le compromis, surtout depuis que les tests sont au courant de la scala de version dans le processus de libération. Je pourrais vivre avec un processus qui n'est pas en deux étapes comme le plugin maven, mais n'en œuvre multi-version de test et de publier.

Tout commentaire supplémentaire qui peut me faire sur le dernier mile serait appréciée.

12voto

Jon-Anders Teigen Points 261

La plupart de ce qui est bien pris en charge dans sbt dans un arbre source

Version spécifique de la source de répertoires sont généralement pas besoin. Scala programmes tend à être compatible - souvent dans le fait que crossbuilding (http://www.scala-sbt.org/release/docs/Detailed-Topics/Cross-Build) a le soutien de première classe dans le sbt.

Si vous avez vraiment besoin de la version spécifique de code, vous pouvez ajouter d'autres dossiers de la source. Mettre ceci dans votre construction.sbt fichier ajouter "src/main/scala-[scalaVersion]" comme une source de répertoire pour chaque version que vous crossbuild en plus de l'ordinaire "src/main/scala". (il existe également un plugin pour générer des cales entre la version, mais je n'ai pas essayé - https://github.com/sbt/sbt-scalashim)

unmanagedSourceDirectories in Compile <+= (sourceDirectory in Compile, scalaVersion){ (s,v) => s / ("scala-"+v) }

version spécifique de la source de pots - voir crossbuilding, fonctionne hors de la boîte

intégré au déploiement https://github.com/sbt/sbt-release (a impressionnant de l'intégration de git trop)

Maven utilisateurs finaux- http://www.scala-sbt.org/release/docs/Detailed-Topics/Publishing.html

Ombragée - j'ai utilisé cette un https://github.com/sbt/sbt-assembly qui ont bien fonctionné pour mes besoins. Votre problème avec l'assemblée plugin peut être résolu par une réécriture de l'généré pom. Voici un exemple de l'extraction des 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
        }
    })
}

Construction complète.sbt pour des fins de référence

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

2voto

Sean Parsons Points 2132

J'ai fait quelque chose de semblable avec SBT comme exemple: https://github.com/seanparsons/scalaz/commit/21298eb4af80f107181bfd09eaaa51c9b56bdc28

Il est rendu possible par SBT permettant à tous les paramètres à déterminer en fonction d'autres paramètres, ce qui signifie que la plupart des autres choses, il faut "juste travail".

Aussi loin que l'pom.xml aspect que je ne peux que recommander de poser la question dans le SBT liste de diffusion, je serais surpris si vous ne pouvait pas le faire cependant.

0voto

Erik van Oosten Points 121

Mon article de blog http://www.day-to-day-stuff.blogspot.nl/2013/04/fixing-code-and-binary.html contient un exemple d'une solution légèrement plus fine pour attacher différents répertoires sources; un par grand S. Il explique également comment créer un code spécifique à la version scala qui peut être utilisé par du code non spécifique.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X