Akka Extras использует полный .scala
синтаксис SBT. Это отличается от .sbt
синтаксиса, поэтому давайте рассмотрим, как создать синтаксическую сборку Scala, включая публикацию в Sonatype. Мы исследуем это на реальном EigengoBuild
объекте .
Строительный объект
EigengoBuild
Расширяет Build
объект, который является настройкой проекта. В этом файле мы определим модули, а также root
модуль, который объединяет дочерние модули. Давайте рассмотрим общую структуру.
object EigengoBuild extends Build { // contains the modules and build settings } object Publish { // contains settings for publishing } object Dependencies { // contains dependencies }
Давайте рассмотрим EigengoBuild
основную структуру России. Начнем с настроек и модулей. settings
И defaultSettings
провести глобальные и модуль конкретных параметров SBT. Затем мы ссылаемся и используем эти последовательности настроек.
override val settings
Имеет глобальные параметры проекта. Мы устанавливаем organisation
, version
и scalaVersion
настройки SBT. defaultSettings
Содержит настройки , которые будут использоваться в каждом модуле. К ним относятся параметры компилятора (scalac и javac), поведение потоков и средства разрешения артефактов. Если у вас есть локальный / корпоративный репозиторий, вам нужно будет добавить его в resolvers
последовательность. Обратите внимание, что некоторые ключи в настройках извлекаются из нашего Publish
объекта, а также из объектов, которые определяют плагины. ( Ex gratia graphSettings
, определено в net.virtualvoid.sbt.graph.Plugin
.)
object EigengoBuild extends Build { override val settings = super.settings ++ Seq( organization := "org.eigengo.akka-extras", version := "0.1.0", scalaVersion := "2.10.1" ) lazy val defaultSettings = Defaults.defaultSettings ++ Publish.settings ++ graphSettings ++ Seq( scalacOptions in Compile ++= Seq("-encoding", "UTF-8", "-target:jvm-1.6", "-deprecation", "-unchecked"), javacOptions in Compile ++= Seq("-source", "1.6", "-target", "1.6", "-Xlint:unchecked", "-Xlint:deprecation", "-Xlint:-options"), // https://github.com/sbt/sbt/issues/702 javaOptions += "-Djava.util.logging.config.file=logging.properties", javaOptions += "-Xmx2G", outputStrategy := Some(StdoutOutput), fork := true, maxErrors := 1, resolvers ++= Seq( Resolver.mavenLocal, Resolver.sonatypeRepo("releases"), Resolver.typesafeRepo("releases"), "Spray Releases" at "http://repo.spray.io", Resolver.typesafeRepo("snapshots"), Resolver.sonatypeRepo("snapshots") ), parallelExecution in Test := false ) ++ ScctPlugin.instrumentSettings // ++ ScalastylePlugin.Settings ... }
Теперь, когда у нас есть настройки, мы можем определить модули и получить настройки, которые мы определили выше. Здесь у нас есть все модули, которые составляют Akka Extras. Мы используем подчеркивание для имени переменной и тире для имени каталога. Итак, apple_push
переменная определяет модуль, который живет в apple-push
каталоге.
Модули включают settings
, которые обычно определяют libraryDependencies
. Переменные, в которых хранятся зависимости, определяются ниже в Dependencies
объекте. (Таким образом, import Dependencies._
выше.) В каждом каталоге, мы имеем обычную Maven-эск структуру src/main/scala
, src/main/resources
; src/test/scala
и так далее.
object EigengoBuild extends Build { override val settings = ... lazy val defaultSettings = Defaults.defaultSettings ++ Publish.settings ++ graphSettings ++ ... def module(dir: String) = Project(id = dir, base = file(dir), settings = defaultSettings) import Dependencies._ lazy val apple_push = module("apple-push") settings( libraryDependencies += akka, libraryDependencies += specs2 % "test" ) lazy val freemarker_templating = module("freemarker-templating") settings ( libraryDependencies += freemarker, libraryDependencies += specs2 % "test" ) lazy val javamail = module("javamail") settings ( libraryDependencies += mail, libraryDependencies += scalaz_core, libraryDependencies += typesafe_config, libraryDependencies += akka, libraryDependencies += specs2 % "test", libraryDependencies += dumbster % "test", libraryDependencies += akka_testkit % "test", publishArtifact in Compile := true ) lazy val main = module("main") dependsOn(apple_push, freemarker_templating, javamail) ... }
Мы почти в конце. Последнее, что нам нужно сделать, это объединить все эти проекты в root
проект. Дальше нет libraryDependencies
, но включены все остальные модули.
object EigengoBuild extends Build { ... lazy val root = Project( id = "parent", base = file("."), settings = defaultSettings ++ ScctPlugin.mergeReportSettings ++ Seq(publishArtifact in Compile := false), aggregate = Seq(apple_push, freemarker_templating, javamail) ) }
зависимости
В полноценных сборках Scala мы определяем индивидуальные зависимости как переменные; имеет смысл отделить их от их собственного объекта. И это именно то, что мы сделали в Dependencies
объекте
object Dependencies { val akka_version = "2.1.2" val akka = "com.typesafe.akka" %% "akka-actor" % akka_version val scalaz_core = "org.scalaz" %% "scalaz-core" % "7.0.0" val typesafe_config = "com.typesafe" % "config" % "1.0.0" val akka_testkit = "com.typesafe.akka" %% "akka-testkit" % akka_version val specs2 = "org.specs2" %% "specs2" % "1.14" val mail = "javax.mail" % "mail" % "1.4.2" val freemarker = "org.freemarker" % "freemarker" % "2.3.19" val dumbster = "dumbster" % "dumbster" % "1.6" }
Публикация и Публикация объекта
Мы публикуем наши артефакты на хостинге Sonatype OSS ; и мы используем sbt-release
плагин. Плагину нужны некоторые настройки, которые мы определяем в Publish
объекте. Код соответствует руководству по публикации , но использует .scala
синтаксис вместо полноценного .sbt
.
Мы определяем settings
переменную: последовательность настроек SBT, которая является Scala-синтаксическим эквивалентом написания
pomExtra := ... publishTo := ...
и другие в .sbt
синтаксисе. Чтобы все было читабельно, мы вытащили фактические значения вроде akkaExtrasPomExtra
, что является правильной переменной в Publish
объекте; и мы обращаемся к нему, когда строим настройки SBT в этой последовательности. (А именно pomExtra := akkaExtrasPomExtra
)
akkaExtrasCredentials
Загружается из ~/.sonatype
файла. (Вы не хотите публиковать свои учетные данные на GitHub — помните печальный эпизод, когда люди нажимали свои закрытые ключи без ключевой фразы?)
Этот файл должен содержать realm
, host
, username
и password
свойство типа линий.
realm=Sonatype Nexus Repository Manager host=oss.sonatype.org user=yeahright password=likeidtellyou
Итак, вперед к Publish
объекту.
object Publish { lazy val settings = Seq( crossPaths := false, pomExtra := akkaExtrasPomExtra, publishTo < <= version { v: String => val nexus = "https://oss.sonatype.org/" if (v.trim.endsWith("SNAPSHOT")) Some("snapshots" at nexus + "content/repositories/snapshots") else Some("releases" at nexus + "service/local/staging/deploy/maven2") }, credentials ++= akkaExtrasCredentials, organizationName := "Eigengo", organizationHomepage := Some(url("http://www.eigengo.com")), publishMavenStyle := true, // Maven central cannot allow other repos. // TODO - Make sure all artifacts are on central. pomIncludeRepository := { x => false } ) val akkaExtrasPomExtra = ( <url>http://www.eigengo.org/akka-extras</url> ... ) val akkaExtrasCredentials = Seq(Credentials(Path.userHome / ".sonatype")) }
Резюме
На этом мы завершаем статью о том, как мы строим многомодульный проект Akka Extras. Я надеюсь, что вы найдете это полезным для ваших собственных проектов. Исходный код находится по адресу https://github.com/eigengo/akka-extras .