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 .