From 84ab235882334a1ec8808b1d0abd9163b069b0aa Mon Sep 17 00:00:00 2001 From: Marcos Pereira Date: Mon, 25 Mar 2019 21:31:44 -0400 Subject: [PATCH] Use sbt 1 to build Lagom itself (#1819) (#1827) Fixes #1329 (cherry picked from commit 44abb8c5c06e23f6d4c8c7e47dd733c97fefee52) --- bin/test-2.11 | 2 +- bin/test-2.12 | 2 +- bin/test-code-style | 17 +-- build.sbt | 103 ++++++------------ .../lightbend/lagom/dev/PortAssigner.scala | 2 +- .../lagom/dev/PortAssignerSpec.scala | 6 +- .../internal/kafka/KafkaLocalServer.scala | 4 +- .../lagom/sbt/scripted/ScriptedTools.scala | 2 +- .../discovery/ServiceLocatorServer.scala | 4 +- docs/build.sbt | 6 +- .../guide/devmode/code/dev-environment.sbt | 1 + docs/project/build.properties | 2 +- docs/project/plugins.sbt | 14 +-- .../javadsl/persistence/ReadSideActor.scala | 24 ++-- .../scaladsl/persistence/ReadSideActor.scala | 24 ++-- .../persistence/PersistentEntity.scala | 4 +- project/Dependencies.scala | 3 +- project/Doc.scala | 13 ++- project/Protobuf.scala | 82 +++++++++++--- project/SbtMavenPlugin.scala | 2 +- project/build.properties | 2 +- project/plugins.sbt | 30 ++--- project/project/buildinfo.sbt | 2 +- .../javadsl/api/PathParamSerializers.scala | 6 +- .../lagom/internal/javadsl/api/ScalaSig.scala | 2 +- .../lagom/javadsl/testkit/ServiceTest.scala | 4 +- 26 files changed, 190 insertions(+), 173 deletions(-) diff --git a/bin/test-2.11 b/bin/test-2.11 index fb251a20c9..a7e2407217 100755 --- a/bin/test-2.11 +++ b/bin/test-2.11 @@ -2,4 +2,4 @@ . "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/scriptLib" -runSbtNoisy "+++2.11.12 test" +runSbtNoisy "++2.11.12 test" diff --git a/bin/test-2.12 b/bin/test-2.12 index 68ba5f8592..7a315ae1fa 100755 --- a/bin/test-2.12 +++ b/bin/test-2.12 @@ -2,4 +2,4 @@ . "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/scriptLib" -runSbtNoisy "+++2.12.8 test" +runSbtNoisy "++2.12.8 test" diff --git a/bin/test-code-style b/bin/test-code-style index 4d4f364444..a568de050e 100755 --- a/bin/test-code-style +++ b/bin/test-code-style @@ -2,14 +2,15 @@ . "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/scriptLib" -runSbt scalariformFormat \ - test:scalariformFormat \ - multi-jvm:scalariformFormat \ - checkHeaders \ - test:checkHeaders \ - multi-jvm:checkHeaders \ - validateDependencies \ - mimaCheckOneAtATime +runSbt \ + scalariformFormat \ + test:scalariformFormat \ + multi-jvm:scalariformFormat \ + headerCheck \ + test:headerCheck \ + multi-jvm:headerCheck \ + validateDependencies \ + mimaReportBinaryIssues git diff --exit-code || ( echo "ERROR: Scalariform check failed, see differences above." diff --git a/build.sbt b/build.sbt index 48dd610c08..e9f5b4dc49 100644 --- a/build.sbt +++ b/build.sbt @@ -8,9 +8,7 @@ import com.typesafe.sbt.SbtMultiJvm.MultiJvmKeys._ import com.typesafe.sbt.SbtMultiJvm.MultiJvmKeys.MultiJvm import lagom.Protobuf import com.typesafe.sbt.SbtScalariform.ScalariformKeys -import de.heikoseeberger.sbtheader.{ HeaderKey, HeaderPattern } import com.typesafe.tools.mima.core._ -import sbt.CrossVersion._ // Turn off "Resolving" log messages that clutter build logs ivyLoggingLevel in ThisBuild := UpdateLogging.Quiet @@ -40,22 +38,10 @@ def common: Seq[Setting[_]] = releaseSettings ++ bintraySettings ++ evictionSett licenses := Seq(("Apache-2.0", url("http://www.apache.org/licenses/LICENSE-2.0.html"))), homepage := Some(url("https://www.lagomframework.com/")), sonatypeProfileName := "com.lightbend", - headers := headers.value ++ Map( - "scala" -> ( - HeaderPattern.cStyleBlockComment, - """|/* - | * Copyright (C) 2016-2019 Lightbend Inc. - | */ - |""".stripMargin - ), - "java" -> ( - HeaderPattern.cStyleBlockComment, - """|/* - | * Copyright (C) 2016-2019 Lightbend Inc. - | */ - |""".stripMargin - ) - ), + headerLicense := Some(HeaderLicense.Custom( + "Copyright (C) 2016-2019 Lightbend Inc. " + )), + headerEmptyLine := false, pomExtra := { @@ -140,7 +126,7 @@ def releaseStepCommandAndRemaining(command: String): State => State = { original if (newState.remainingCommands.isEmpty) { newState } else { - runCommand(newState.remainingCommands.head, newState.copy(remainingCommands = newState.remainingCommands.tail)) + runCommand(newState.remainingCommands.head.commandLine, newState.copy(remainingCommands = newState.remainingCommands.tail)) } } @@ -168,8 +154,6 @@ def runtimeLibCommon: Seq[Setting[_]] = common ++ runtimeScalaSettings ++ Seq( Dependencies.pruneWhitelistSetting, Dependencies.dependencyWhitelistSetting, - incOptions := incOptions.value.withNameHashing(true), - // show full stack traces and test case durations testOptions in Test += Tests.Argument("-oDF"), // -v Log "test run started" / "test started" / "test run finished" events on log level "info" instead of "debug". @@ -183,7 +167,10 @@ def formattingPreferences = { .setPreference(RewriteArrowSymbols, false) .setPreference(AlignParameters, true) .setPreference(AlignSingleLineCaseStatements, true) + .setPreference(AllowParamGroupsOnNewlines, true) .setPreference(SpacesAroundMultiImports, true) + .setPreference(DanglingCloseParenthesis, Force) + .setPreference(AlignArguments, false) } val defaultMultiJvmOptions: List[String] = { @@ -193,11 +180,11 @@ val defaultMultiJvmOptions: List[String] = { // -Djava.net.preferIPv4Stack=true or -Dmultinode.Xmx512m val MultinodeJvmArgs = "multinode\\.(D|X)(.*)".r val knownPrefix = Set("akka.", "lagom.") - val properties = System.getProperties.propertyNames.asScala.toList.collect { + val properties = System.getProperties.stringPropertyNames.asScala.toList.collect { case MultinodeJvmArgs(a, b) => val value = System.getProperty("multinode." + a + b) "-" + a + b + (if (value == "") "" else "=" + value) - case key: String if knownPrefix.exists(pre => key.startsWith(pre)) => "-D" + key + "=" + System.getProperty(key) + case key if knownPrefix.exists(pre => key.startsWith(pre)) => "-D" + key + "=" + System.getProperty(key) } "-Xmx128m" :: properties @@ -229,8 +216,8 @@ def multiJvmTestSettings: Seq[Setting[_]] = { forkedTests ++ // enabling HeaderPlugin in MultiJvm requires two sets of settings. // see https://github.com/sbt/sbt-header/issues/37 - HeaderPlugin.settingsFor(MultiJvm) ++ - AutomateHeaderPlugin.automateFor(MultiJvm) ++ + headerSettings(MultiJvm) ++ + automateHeaderSettings(MultiJvm) ++ inConfig(MultiJvm)(SbtScalariform.configScalariformSettings) ++ (compileInputs in(MultiJvm, compile) := { (compileInputs in(MultiJvm, compile)) dependsOn (scalariformFormat in MultiJvm) @@ -247,11 +234,15 @@ def multiJvmTestSettings: Seq[Setting[_]] = { executeTests in Test := { val testResults = (executeTests in Test).value val multiNodeResults = (executeTests in MultiJvm).value - val overall = - if (testResults.overall.id < multiNodeResults.overall.id) - multiNodeResults.overall - else - testResults.overall + import TestResult.{ Passed, Failed, Error } + val overall = (testResults.overall, multiNodeResults.overall) match { + case (Passed, Passed) => Passed + case (Failed, Failed) => Failed + case (Error, Error) => Error + case (Passed, Failed) | (Failed, Passed) => Failed + case (Passed, Error) | (Error, Passed) => Error + case (Failed, Error) | (Error, Failed) => Error + } Tests.Output(overall, testResults.events ++ multiNodeResults.events, testResults.summaries ++ multiNodeResults.summaries) @@ -265,7 +256,7 @@ def macroCompileSettings: Seq[Setting[_]] = Seq( compile in Test ~= { a => // Delete classes in "compile" packages after compiling. // These are used for compile-time tests and should be recompiled every time. - val products = a.relations.allProducts.toSeq ** new SimpleFileFilter(_.getParentFile.getName == "compile") + val products = (a.asInstanceOf[sbt.internal.inc.Analysis]).relations.allProducts.toSeq ** new SimpleFileFilter(_.getParentFile.getName == "compile") IO.delete(products.get) a } @@ -370,9 +361,8 @@ val sbtScriptedProjects = Seq[Project]( lazy val root = (project in file(".")) .settings(name := "lagom") .settings(runtimeLibCommon: _*) - .enablePlugins(CrossPerProjectPlugin) .settings( - crossScalaVersions := Dependencies.ScalaVersions, + crossScalaVersions := Nil, scalaVersion := Dependencies.ScalaVersions.head, PgpKeys.publishSigned := {}, publishLocal := {}, @@ -653,12 +643,12 @@ def forkedTests: Seq[Setting[_]] = Seq( def singleTestsGrouping(tests: Seq[TestDefinition]) = { // We could group non Cassandra tests into another group // to avoid new JVM for each test, see http://www.scala-sbt.org/release/docs/Testing.html - val javaOptions = Seq("-Xms256M", "-Xmx512M") + val javaOptions = Vector("-Xms256M", "-Xmx512M") tests map { test => Tests.Group( name = test.name, tests = Seq(test), - runPolicy = Tests.SubProcess(ForkOptions(runJVMOptions = javaOptions)) + runPolicy = Tests.SubProcess(ForkOptions().withRunJVMOptions(javaOptions)) ) } } @@ -1093,10 +1083,9 @@ lazy val `sbt-build-tool-support` = (project in file("dev") / "build-tool-suppor lazy val `sbt-plugin` = (project in file("dev") / "sbt-plugin") .settings(common: _*) .settings(scriptedSettings: _*) - .enablePlugins(SbtPluginPlugins) + .enablePlugins(SbtPluginPlugins, SbtPlugin) .settings( name := "lagom-sbt-plugin", - sbtPlugin := true, crossScalaVersions := Dependencies.SbtScalaVersions, scalaVersion := Dependencies.SbtScalaVersions.head, sbtVersion in pluginCrossBuild := defineSbtVersion(scalaBinaryVersion.value), @@ -1116,10 +1105,11 @@ lazy val `sbt-plugin` = (project in file("dev") / "sbt-plugin") val () = (publishLocal in `sbt-scripted-library`).value }, publishTo := { + val old = publishTo.value if (isSnapshot.value) { // Bintray doesn't support publishing snapshots, publish to Sonatype snapshots instead Some(Opts.resolver.sonatypeSnapshots) - } else publishTo.value + } else old }, publishMavenStyle := isSnapshot.value ).dependsOn(`sbt-build-tool-support`) @@ -1153,7 +1143,7 @@ lazy val `maven-launcher` = (project in file("dev") / "maven-launcher") Dependencies.`maven-launcher` ) -def scriptedSettings: Seq[Setting[_]] = ScriptedPlugin.scriptedSettings ++ +def scriptedSettings: Seq[Setting[_]] = Seq(scriptedLaunchOpts += s"-Dproject.version=${version.value}") ++ Seq( scripted := scripted.tag(Tags.Test).evaluated, @@ -1200,7 +1190,7 @@ def archetypeProject(archetypeName: String) = (unmanagedResources in Compile).value ++ gitIgnoreFiles }, // Don't force copyright headers in Maven archetypes - HeaderKey.excludes := Seq("*") + excludeFilter in headerResources := "*" ) lazy val `maven-java-archetype` = archetypeProject("java") @@ -1225,7 +1215,7 @@ lazy val `maven-dependencies` = (project in file("dev") / "maven-dependencies") Dependencies.ScalaVersions.map { supportedVersion => // we are sure this won't be a None val crossFunc = - CrossVersion(new Binary(binaryScalaVersion), supportedVersion, binaryScalaVersion(supportedVersion)).get + CrossVersion(Binary(), supportedVersion, CrossVersion.binaryScalaVersion(supportedVersion)).get // convert artifactName to match the desired scala version val artifactId = crossFunc(artifactName) @@ -1264,7 +1254,7 @@ lazy val `maven-dependencies` = (project in file("dev") / "maven-dependencies") // if it's a Scala dependency, // generate block for each supported scala version Dependencies.ScalaVersions.map { supportedVersion => - val crossDep = CrossVersion(supportedVersion, binaryScalaVersion(supportedVersion))(dep) + val crossDep = CrossVersion(supportedVersion, CrossVersion.binaryScalaVersion(supportedVersion))(dep) {crossDep.organization} {crossDep.name} @@ -1276,11 +1266,11 @@ lazy val `maven-dependencies` = (project in file("dev") / "maven-dependencies") } - } - ).settings( + }, // This disables creating jar, source jar and javadocs, and will cause the packaging type to be "pom" when the // pom is created - Classpaths.defaultPackageKeys.map(key => publishArtifact in key := false): _* + Classpaths.defaultPackageKeys.map(key => publishArtifact in key := false), + publishMavenStyle := true, // Disable publishing ("delivering") the ivy.xml file ) // This project doesn't get aggregated, it is only executed by the sbt-plugin scripted dependencies @@ -1400,26 +1390,3 @@ lazy val `macro-testkit` = (project in file("macro-testkit")) PgpKeys.publishSigned := {}, publish := {} ) - -// We can't just run a big aggregated mimaReportBinaryIssues due to -// https://github.com/typesafehub/migration-manager/issues/163 -// Travis doesn't provide us enough memory to do so. So instead, we -// run the binary compatibility checks one at a time, which works -// around the issue. -commands += Command.command("mimaCheckOneAtATime") { state => - val extracted = Project.extract(state) - val results = (javadslProjects ++ scaladslProjects).map { project => - println(s"Checking binary compatibility for ${project.id}") - try { - extracted.runTask(mimaReportBinaryIssues in project, state) - true - } catch { - case scala.util.control.NonFatal(e) => false - } - } - - if (results.contains(false)) { - throw new FeedbackProvidedException {} - } - state -} diff --git a/dev/build-tool-support/src/main/scala/com/lightbend/lagom/dev/PortAssigner.scala b/dev/build-tool-support/src/main/scala/com/lightbend/lagom/dev/PortAssigner.scala index 395d4fc223..a00a6325dd 100644 --- a/dev/build-tool-support/src/main/scala/com/lightbend/lagom/dev/PortAssigner.scala +++ b/dev/build-tool-support/src/main/scala/com/lightbend/lagom/dev/PortAssigner.scala @@ -59,7 +59,7 @@ object PortAssigner { @annotation.tailrec def loop(projectNames: Seq[ProjectName], assignedPort: Set[Port], unassigned: Vector[ProjectName], result: Map[ProjectName, Port]): Map[ProjectName, Port] = projectNames match { case Nil if unassigned.nonEmpty => - // if we are here there are projects with colliding hash that still need to get their port assigned. As expected, this step is carried out after assigning + // if we are here there are projects with colliding hash that still need to get their port assigned. As expected, this step is carried out after assigning // a port to all non-colliding projects. val proj = unassigned.head val projectedPort = projectedPortFor(proj) diff --git a/dev/build-tool-support/src/test/scala/com/lightbend/lagom/dev/PortAssignerSpec.scala b/dev/build-tool-support/src/test/scala/com/lightbend/lagom/dev/PortAssignerSpec.scala index 637bdd901d..478e5f6861 100644 --- a/dev/build-tool-support/src/test/scala/com/lightbend/lagom/dev/PortAssignerSpec.scala +++ b/dev/build-tool-support/src/test/scala/com/lightbend/lagom/dev/PortAssignerSpec.scala @@ -81,9 +81,9 @@ class PortAssignerSpec extends WordSpecLike with Matchers { } "assign ports first to projects with non-colliding hash/port" in { - // Using the range is key to exercise the expected functionality. Basically, we want to check that + // Using the range is key to exercise the expected functionality. Basically, we want to check that // the port assigned to `projC` cannot be affected by `projB`, which happens to have the same hash of `projA`. - // Said otherwise, projects with non colliding hash should get their port assigned **before** projects + // Said otherwise, projects with non colliding hash should get their port assigned **before** projects // that result in a port collision. val portRange = PortRange(7, 9) @@ -103,7 +103,7 @@ class PortAssignerSpec extends WordSpecLike with Matchers { val projectsWithCollisions = Seq(projA, projB, projC) val projectName2portWithCollisions = PortAssigner.computeProjectsPort(portRange, projectsWithCollisions) - // Note how project A and C have still got assigned the same port, while project B will get the next available port, counting + // Note how project A and C have still got assigned the same port, while project B will get the next available port, counting // from 7 (which is project's A port). That turns out to be port 9. projectName2portWithCollisions(projA) shouldBe Port(7) projectName2portWithCollisions(projC) shouldBe Port(8) diff --git a/dev/kafka-server/src/main/scala/com/lightbend/lagom/internal/kafka/KafkaLocalServer.scala b/dev/kafka-server/src/main/scala/com/lightbend/lagom/internal/kafka/KafkaLocalServer.scala index 430702db3c..0347dbe9cb 100644 --- a/dev/kafka-server/src/main/scala/com/lightbend/lagom/internal/kafka/KafkaLocalServer.scala +++ b/dev/kafka-server/src/main/scala/com/lightbend/lagom/internal/kafka/KafkaLocalServer.scala @@ -28,8 +28,8 @@ class KafkaLocalServer private (kafkaProperties: Properties, zooKeeperServer: Ka def start(): Unit = { if (kafkaServerRef.get == null) { - // There is a possible race condition here. However, instead of attempting to avoid it - // by using a lock, we are working with it and do the necessary clean up if indeed we + // There is a possible race condition here. However, instead of attempting to avoid it + // by using a lock, we are working with it and do the necessary clean up if indeed we // end up creating two Kafka server instances. val newKafkaServer = KafkaServerStartable.fromProps(kafkaProperties) if (kafkaServerRef.compareAndSet(null, newKafkaServer)) { diff --git a/dev/sbt-scripted-tools/src/main/scala/com/lightbend/lagom/sbt/scripted/ScriptedTools.scala b/dev/sbt-scripted-tools/src/main/scala/com/lightbend/lagom/sbt/scripted/ScriptedTools.scala index 3c0e4e870e..fffa117c46 100644 --- a/dev/sbt-scripted-tools/src/main/scala/com/lightbend/lagom/sbt/scripted/ScriptedTools.scala +++ b/dev/sbt-scripted-tools/src/main/scala/com/lightbend/lagom/sbt/scripted/ScriptedTools.scala @@ -136,7 +136,7 @@ object ScriptedTools extends AutoPlugin { uri: Option[URI] = None, retry: Boolean = false, shouldBeDown: Boolean = false, - statusAssertion: Int => Unit = _ => (), + statusAssertion: Int => Unit = _ => (), bodyAssertion: String => Unit = _ => () ) diff --git a/dev/service-registry/service-locator/src/main/scala/com/lightbend/lagom/discovery/ServiceLocatorServer.scala b/dev/service-registry/service-locator/src/main/scala/com/lightbend/lagom/discovery/ServiceLocatorServer.scala index a34167797f..8ace1cf4bd 100644 --- a/dev/service-registry/service-locator/src/main/scala/com/lightbend/lagom/discovery/ServiceLocatorServer.scala +++ b/dev/service-registry/service-locator/src/main/scala/com/lightbend/lagom/discovery/ServiceLocatorServer.scala @@ -75,8 +75,8 @@ class ServiceLocatorServer extends Closeable { } def serviceLocatorAddress: URI = { - // Converting InetSocketAddress into URL is not that simple. - // Because we know the service locator is running locally, I'm hardcoding the hostname and protocol. + // Converting InetSocketAddress into URL is not that simple. + // Because we know the service locator is running locally, I'm hardcoding the hostname and protocol. new URI(s"http://localhost:${server.mainAddress.getPort}") } diff --git a/docs/build.sbt b/docs/build.sbt index c7c267f6c7..63e465ee27 100644 --- a/docs/build.sbt +++ b/docs/build.sbt @@ -12,6 +12,7 @@ val HibernateVersion = "5.2.12.Final" val ValidationApiVersion = "2.0.1.Final" val branch = { + import scala.sys.process._ val rev = "git rev-parse --abbrev-ref HEAD".!!.trim if (rev == "HEAD") { // not on a branch, get the hash @@ -128,12 +129,13 @@ def forkedTests: Seq[Setting[_]] = Seq( def singleTestsGrouping(tests: Seq[TestDefinition]) = { // We could group non Cassandra tests into another group // to avoid new JVM for each test, see https://www.scala-sbt.org/release/docs/Testing.html - val javaOptions = Seq("-Xms256M", "-Xmx512M") + val javaOptions = Vector("-Xms256M", "-Xmx512M") tests map { test => new Tests.Group( name = test.name, tests = Seq(test), - runPolicy = Tests.SubProcess(javaOptions)) + runPolicy = Tests.SubProcess(ForkOptions().withRunJVMOptions(javaOptions)), + ) } } diff --git a/docs/manual/common/guide/devmode/code/dev-environment.sbt b/docs/manual/common/guide/devmode/code/dev-environment.sbt index 5bf964559a..9a571c6f6f 100644 --- a/docs/manual/common/guide/devmode/code/dev-environment.sbt +++ b/docs/manual/common/guide/devmode/code/dev-environment.sbt @@ -21,6 +21,7 @@ startElasticSearch in ThisBuild := { elasticsearch / "bin" / "elasticsearch" } + import scala.sys.process._ val process = Process(binFile.getAbsolutePath, elasticsearch).run(log) log.info("Elastic search started on port 9200") diff --git a/docs/project/build.properties b/docs/project/build.properties index 133a8f197e..c0bab04941 100644 --- a/docs/project/build.properties +++ b/docs/project/build.properties @@ -1 +1 @@ -sbt.version=0.13.17 +sbt.version=1.2.8 diff --git a/docs/project/plugins.sbt b/docs/project/plugins.sbt index 2ee13b5062..c53c32def6 100644 --- a/docs/project/plugins.sbt +++ b/docs/project/plugins.sbt @@ -2,13 +2,11 @@ lazy val plugins = (project in file(".")).dependsOn(dev) lazy val dev = ProjectRef(Path.fileProperty("user.dir").getParentFile, "sbt-plugin") -resolvers += Resolver.typesafeIvyRepo("releases") -addSbtPlugin("com.lightbend.markdown" %% "sbt-lightbend-markdown" % "1.6.1") +addSbtPlugin("com.lightbend.markdown" %% "sbt-lightbend-markdown" % "1.7.0") -// Needed for bintray configuration code samples -addSbtPlugin("me.lessis" % "bintray-sbt" % "0.3.0") +addSbtPlugin("org.foundweekends" % "sbt-bintray" % "0.5.4") -addSbtPlugin("com.typesafe.sbt" % "sbt-web" % "1.2.2") -addSbtPlugin("com.typesafe.sbt" % "sbt-twirl" % "1.1.1") -addSbtPlugin("com.typesafe.sbt" % "sbt-less" % "1.1.1") -addSbtPlugin("com.typesafe.sbt" % "sbt-uglify" % "1.0.3") +addSbtPlugin("com.typesafe.sbt" % "sbt-web" % "1.4.4") +addSbtPlugin("com.typesafe.sbt" % "sbt-twirl" % "1.4.0") +addSbtPlugin("com.typesafe.sbt" % "sbt-less" % "1.1.2") +addSbtPlugin("com.typesafe.sbt" % "sbt-uglify" % "2.0.0") diff --git a/persistence/javadsl/src/main/scala/com/lightbend/lagom/internal/javadsl/persistence/ReadSideActor.scala b/persistence/javadsl/src/main/scala/com/lightbend/lagom/internal/javadsl/persistence/ReadSideActor.scala index 198d40001f..a5e2cdd764 100644 --- a/persistence/javadsl/src/main/scala/com/lightbend/lagom/internal/javadsl/persistence/ReadSideActor.scala +++ b/persistence/javadsl/src/main/scala/com/lightbend/lagom/internal/javadsl/persistence/ReadSideActor.scala @@ -79,18 +79,18 @@ private[lagom] class ReadSideActor[Event <: AggregateEvent[Event]]( config.maxBackoff, config.randomBackoffFactor ) { () => - val handler: ReadSideProcessor.ReadSideHandler[Event] = processorFactory().buildHandler() - val futureOffset = handler.prepare(tag).toScala - scaladsl.Source - .fromFuture(futureOffset) - .initialTimeout(config.offsetTimeout) - .flatMapConcat { - offset => - val eventStreamSource = eventStreamFactory(tag, offset).asScala - val userlandFlow = handler.handle() - eventStreamSource.via(userlandFlow) - } - } + val handler: ReadSideProcessor.ReadSideHandler[Event] = processorFactory().buildHandler() + val futureOffset = handler.prepare(tag).toScala + scaladsl.Source + .fromFuture(futureOffset) + .initialTimeout(config.offsetTimeout) + .flatMapConcat { + offset => + val eventStreamSource = eventStreamFactory(tag, offset).asScala + val userlandFlow = handler.handle() + eventStreamSource.via(userlandFlow) + } + } val (killSwitch, streamDone) = backoffSource .viaMat(KillSwitches.single)(Keep.right) diff --git a/persistence/scaladsl/src/main/scala/com/lightbend/lagom/internal/scaladsl/persistence/ReadSideActor.scala b/persistence/scaladsl/src/main/scala/com/lightbend/lagom/internal/scaladsl/persistence/ReadSideActor.scala index ceb8686475..e801a213f2 100644 --- a/persistence/scaladsl/src/main/scala/com/lightbend/lagom/internal/scaladsl/persistence/ReadSideActor.scala +++ b/persistence/scaladsl/src/main/scala/com/lightbend/lagom/internal/scaladsl/persistence/ReadSideActor.scala @@ -77,18 +77,18 @@ private[lagom] class ReadSideActor[Event <: AggregateEvent[Event]]( config.maxBackoff, config.randomBackoffFactor ) { () => - val handler = processor().buildHandler() - val futureOffset = handler.prepare(tag) - Source - .fromFuture(futureOffset) - .initialTimeout(config.offsetTimeout) - .flatMapConcat { - offset => - val eventStreamSource = eventStreamFactory(tag, offset) - val userlandFlow = handler.handle() - eventStreamSource.via(userlandFlow) - } - } + val handler = processor().buildHandler() + val futureOffset = handler.prepare(tag) + Source + .fromFuture(futureOffset) + .initialTimeout(config.offsetTimeout) + .flatMapConcat { + offset => + val eventStreamSource = eventStreamFactory(tag, offset) + val userlandFlow = handler.handle() + eventStreamSource.via(userlandFlow) + } + } val (killSwitch, streamDone) = backoffSource .viaMat(KillSwitches.single)(Keep.right) diff --git a/persistence/scaladsl/src/main/scala/com/lightbend/lagom/scaladsl/persistence/PersistentEntity.scala b/persistence/scaladsl/src/main/scala/com/lightbend/lagom/scaladsl/persistence/PersistentEntity.scala index 29bc971a28..cf32201608 100644 --- a/persistence/scaladsl/src/main/scala/com/lightbend/lagom/scaladsl/persistence/PersistentEntity.scala +++ b/persistence/scaladsl/src/main/scala/com/lightbend/lagom/scaladsl/persistence/PersistentEntity.scala @@ -104,8 +104,8 @@ abstract class PersistentEntity { type Behavior = State => Actions type EventHandler = PartialFunction[(Event, State), State] - private[lagom]type CommandHandler = PartialFunction[(Command, CommandContext[Any], State), Persist] - private[lagom]type ReadOnlyCommandHandler = PartialFunction[(Command, ReadOnlyCommandContext[Any], State), Unit] + private[lagom] type CommandHandler = PartialFunction[(Command, CommandContext[Any], State), Persist] + private[lagom] type ReadOnlyCommandHandler = PartialFunction[(Command, ReadOnlyCommandContext[Any], State), Unit] private var _entityId: String = _ diff --git a/project/Dependencies.scala b/project/Dependencies.scala index e1c40527a2..78b1b31a03 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -124,8 +124,7 @@ object Dependencies { "jackson-datatype-jdk8", "jackson-datatype-jsr310", "jackson-datatype-guava", "jackson-datatype-pcollections" ) - - val scalaParserCombinatorOverrides = Set(scalaParserCombinators) + val scalaParserCombinatorOverrides = Seq(scalaParserCombinators) // A whitelist of dependencies that Lagom is allowed to depend on, either directly or transitively. // This list is used to validate all of Lagom's dependencies. diff --git a/project/Doc.scala b/project/Doc.scala index 0c680d273b..69b3e85efd 100644 --- a/project/Doc.scala +++ b/project/Doc.scala @@ -4,8 +4,13 @@ package lagom import sbt._ -import sbtunidoc.Plugin.UnidocKeys._ -import sbtunidoc.Plugin.{Genjavadoc, JavaUnidoc, ScalaUnidoc, scalaJavaUnidocSettings} +import sbtunidoc.{BaseUnidocPlugin, GenJavadocPlugin, JavaUnidocPlugin, ScalaUnidocPlugin} + +import sbtunidoc.BaseUnidocPlugin.autoImport._ +import sbtunidoc.JavaUnidocPlugin.autoImport._ +import sbtunidoc.GenJavadocPlugin.autoImport._ +import sbtunidoc.ScalaUnidocPlugin.autoImport._ + import sbt.Keys._ import sbt.File import sbt.ScopeFilter.ProjectFilter @@ -41,6 +46,8 @@ object UnidocRoot extends AutoPlugin { override def trigger = noTrigger + override def requires = ScalaUnidocPlugin && JavaUnidocPlugin + private def projectsAndDependencies(projects: Seq[ProjectReference]): ProjectFilter = { //projects.map(p => inDependencies(p, transitive = true, includeRoot = true)).reduce(_ || _) projects.map(p => inProjects(p)).reduce(_ || _) @@ -88,7 +95,7 @@ object UnidocRoot extends AutoPlugin { case _ => Seq("--allow-script-in-comments") } - override lazy val projectSettings = scalaJavaUnidocSettings ++ Seq( + override lazy val projectSettings = Seq( unidocAllSources in (JavaUnidoc, unidoc) ++= allGenjavadocSources.value, unidocAllSources in (JavaUnidoc, unidoc) := { (unidocAllSources in (JavaUnidoc, unidoc)).value diff --git a/project/Protobuf.scala b/project/Protobuf.scala index a0f6737454..03403b671e 100644 --- a/project/Protobuf.scala +++ b/project/Protobuf.scala @@ -5,15 +5,17 @@ package lagom import sbt._ -import Process._ -import Keys._ -import com.typesafe.sbt.preprocess.Preprocess._ +import sbt.Keys._ +import sbt.util.CacheStoreFactory +import scala.sys.process._ import java.io.File +import java.io.PrintWriter object Protobuf { val paths = SettingKey[Seq[File]]("protobuf-paths", "The paths that contain *.proto files.") val outputPaths = SettingKey[Seq[File]]("protobuf-output-paths", "The paths where to save the generated *.java files.") + val importPath = SettingKey[Option[File]]("protobuf-import-path", "The path that contain additional *.proto files that can be imported.") val protoc = SettingKey[String]("protobuf-protoc", "The path and name of the protoc executable.") val protocVersion = SettingKey[String]("protobuf-protoc-version", "The version of the protoc executable.") val generate = TaskKey[Unit]("protobuf-generate", "Compile the protobuf sources and do all processing.") @@ -21,18 +23,20 @@ object Protobuf { lazy val settings: Seq[Setting[_]] = Seq( paths := Seq((sourceDirectory in Compile).value, (sourceDirectory in Test).value).map(_ / "protobuf"), outputPaths := Seq((sourceDirectory in Compile).value, (sourceDirectory in Test).value).map(_ / "java"), + importPath := None, protoc := "protoc", protocVersion := "2.6.1", generate := { val sourceDirs = paths.value val targetDirs = outputPaths.value + val log = streams.value.log if (sourceDirs.size != targetDirs.size) sys.error(s"Unbalanced number of paths and destination paths!\nPaths: $sourceDirs\nDestination Paths: $targetDirs") if (sourceDirs exists (_.exists)) { val cmd = protoc.value - val log = streams.value.log + checkProtocVersion(cmd, protocVersion.value, log) val base = baseDirectory.value @@ -40,23 +44,24 @@ object Protobuf { val targets = target.value val cache = targets / "protoc" / "cache" - (sourceDirs zip targetDirs) map { case (src, dst) => - val relative = src.relativeTo(sources).getOrElse(throw new Exception(s"path $src is not a in source tree $sources")).toString - val tmp = targets / "protoc" / relative - IO.delete(tmp) - generate(cmd, src, tmp, log) - transformDirectory(tmp, dst, _ => true, transformFile(_.replace("com.google.protobuf", "akka.protobuf")), cache, log) + (sourceDirs zip targetDirs) map { + case (src, dst) => + val relative = src.relativeTo(sources).getOrElse(throw new Exception(s"path $src is not a in source tree $sources")).toString + val tmp = targets / "protoc" / relative + IO.delete(tmp) + generate(cmd, src, tmp, log, importPath.value) + transformDirectory(tmp, dst, _ => true, transformFile(_.replace("com.google.protobuf", "akka.protobuf")), cache, log) } } - } - ) + }) private def callProtoc[T](protoc: String, args: Seq[String], log: Logger, thunk: (ProcessBuilder, Logger) => T): T = try { val proc = Process(protoc, args) thunk(proc, log) - } catch { case e: Exception => - throw new RuntimeException("error while executing '%s' with args: %s" format(protoc, args.mkString(" ")), e) + } catch { + case e: Exception => + throw new RuntimeException("error while executing '%s' with args: %s" format (protoc, args.mkString(" ")), e) } private def checkProtocVersion(protoc: String, protocVersion: String, log: Logger): Unit = { @@ -67,7 +72,7 @@ object Protobuf { } } - private def generate(protoc: String, srcDir: File, targetDir: File, log: Logger): Unit = { + private def generate(protoc: String, srcDir: File, targetDir: File, log: Logger, importPath: Option[File]): Unit = { val protoFiles = (srcDir ** "*.proto").get if (srcDir.exists) if (protoFiles.isEmpty) @@ -78,10 +83,55 @@ object Protobuf { log.info("Generating %d protobuf files from %s to %s".format(protoFiles.size, srcDir, targetDir)) protoFiles.foreach { proto => log.info("Compiling %s" format proto) } + val protoPathArg = importPath match { + case None => Nil + case Some(p) => Seq("--proto_path", p.absolutePath) + } + val exitCode = callProtoc(protoc, Seq("-I" + srcDir.absolutePath, "--java_out=%s" format targetDir.absolutePath) ++ - protoFiles.map(_.absolutePath), log, { (p, l) => p ! l }) + protoPathArg ++ protoFiles.map(_.absolutePath), log, { (p, l) => p ! l }) if (exitCode != 0) sys.error("protoc returned exit code: %d" format exitCode) } } + + /** + * Create a transformed version of all files in a directory, given a predicate and a transform function for each file. + */ + def transformDirectory(sourceDir: File, targetDir: File, transformable: File => Boolean, transform: (File, File) => Unit, cache: File, log: Logger): File = { + val runTransform = FileFunction.cached(CacheStoreFactory(cache), FilesInfo.hash, FilesInfo.exists) { (in, out) => + val map = Path.rebase(sourceDir, targetDir) + if (in.removed.nonEmpty || in.modified.nonEmpty) { + log.info("Preprocessing directory %s..." format sourceDir) + for (source <- in.removed; target <- map(source)) { + IO delete target + } + val updated = for (source <- in.modified; target <- map(source)) yield { + if (source.isFile) { + if (transformable(source)) transform(source, target) + else IO.copyFile(source, target) + } + target + } + log.info("Directory preprocessed: " + targetDir) + updated + } else Set.empty + } + val sources = sourceDir.allPaths.get.toSet + runTransform(sources) + targetDir + } + + /** + * Transform a file, line by line. + */ + def transformFile(transform: String => String)(source: File, target: File): Unit = { + IO.reader(source) { reader => + IO.writer(target, "", IO.defaultCharset) { writer => + val pw = new PrintWriter(writer) + IO.foreachLine(reader) { line => pw.println(transform(line)) } + } + } + } + } diff --git a/project/SbtMavenPlugin.scala b/project/SbtMavenPlugin.scala index 8e05c10a6a..772ef796aa 100644 --- a/project/SbtMavenPlugin.scala +++ b/project/SbtMavenPlugin.scala @@ -119,7 +119,7 @@ object SbtMavenPlugin extends AutoPlugin { test.getName -> mavenExecutions.foldLeft(true) { (success, execution) => if (success) { log.info(s"Executing mvn $execution") - val rc = Fork.java(ForkOptions(workingDirectory = Some(testDir)), args ++ execution.split(" +")) + val rc = Fork.java(ForkOptions().withWorkingDirectory(testDir), args ++ execution.split(" +")) rc == 0 } else { false diff --git a/project/build.properties b/project/build.properties index 133a8f197e..c0bab04941 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=0.13.17 +sbt.version=1.2.8 diff --git a/project/plugins.sbt b/project/plugins.sbt index 629697b421..f574ff1c5a 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,24 +1,16 @@ // Copyright (C) 2016-2019 Lightbend Inc. -buildInfoSettings -sourceGenerators in Compile += buildInfo.taskValue - -libraryDependencies ++= Seq( - "org.scala-sbt" % "scripted-plugin" % sbtVersion.value -) - -addSbtPlugin("com.eed3si9n" % "sbt-unidoc" % "0.3.3") -addSbtPlugin("de.heikoseeberger" % "sbt-header" % "1.8.0") -addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "0.5.0") -addSbtPlugin("com.github.gseitz" % "sbt-release" % "1.0.3") -addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.0") -addSbtPlugin("me.lessis" % "bintray-sbt" % "0.3.0") -// need this for com.typesafe.sbt.preprocess.Preprocess -addSbtPlugin("com.typesafe.sbt" % "sbt-site" % "0.7.1") -addSbtPlugin("org.scalariform" % "sbt-scalariform" % "1.6.0") -addSbtPlugin("com.typesafe.sbt" % "sbt-multi-jvm" % "0.3.8") +addSbtPlugin("com.eed3si9n" % "sbt-unidoc" % "0.4.2") +addSbtPlugin("de.heikoseeberger" % "sbt-header" % "5.2.0") +addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "2.3") +addSbtPlugin("com.github.gseitz" % "sbt-release" % "1.0.9") +addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.1.1") +addSbtPlugin("org.foundweekends" % "sbt-bintray" % "0.5.4") +addSbtPlugin("com.typesafe.sbt" % "sbt-multi-jvm" % "0.4.0") +addSbtPlugin("org.scalariform" % "sbt-scalariform" % "1.8.2") addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "0.3.0") -addSbtPlugin("com.eed3si9n" % "sbt-doge" % "0.1.5") -addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.8.2") +addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.9.0") addSbtPlugin("com.lightbend" % "sbt-whitesource" % "0.1.14") + +enablePlugins(BuildInfoPlugin) diff --git a/project/project/buildinfo.sbt b/project/project/buildinfo.sbt index aa7300b9cd..22366532fc 100644 --- a/project/project/buildinfo.sbt +++ b/project/project/buildinfo.sbt @@ -1 +1 @@ -addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.3.2") +addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.7.0") diff --git a/service/javadsl/api/src/main/scala/com/lightbend/lagom/internal/javadsl/api/PathParamSerializers.scala b/service/javadsl/api/src/main/scala/com/lightbend/lagom/internal/javadsl/api/PathParamSerializers.scala index 16167f36ab..408ca54f96 100644 --- a/service/javadsl/api/src/main/scala/com/lightbend/lagom/internal/javadsl/api/PathParamSerializers.scala +++ b/service/javadsl/api/src/main/scala/com/lightbend/lagom/internal/javadsl/api/PathParamSerializers.scala @@ -35,9 +35,9 @@ class UnresolvedOptionalPathParamSerializer[Param] extends UnresolvedPathParamSe wrappedType.getTypeName, (subTypeSerializer.deserialize _).compose((p: String) => TreePVector.singleton(p)).asJava, (subTypeSerializer.serialize _).andThen { - case single if single.size() == 1 => single.get(0) - case other => throw new IllegalStateException("Can only wrap an Optional serializer around a path param serializer that produces exactly one parameter") - }.asJava + case single if single.size() == 1 => single.get(0) + case other => throw new IllegalStateException("Can only wrap an Optional serializer around a path param serializer that produces exactly one parameter") + }.asJava ) case _ => throw new IllegalArgumentException("Unresolved Optional path param serializer can only be resolved against ParamaterizedType descriptors for the Optional class. This serializer was resolved against: " + typeInfo) } diff --git a/service/javadsl/api/src/main/scala/com/lightbend/lagom/internal/javadsl/api/ScalaSig.scala b/service/javadsl/api/src/main/scala/com/lightbend/lagom/internal/javadsl/api/ScalaSig.scala index 5a47aba017..d3e45a28b9 100644 --- a/service/javadsl/api/src/main/scala/com/lightbend/lagom/internal/javadsl/api/ScalaSig.scala +++ b/service/javadsl/api/src/main/scala/com/lightbend/lagom/internal/javadsl/api/ScalaSig.scala @@ -6,7 +6,7 @@ package com.lightbend.lagom.internal.javadsl.api import scala.util.matching.Regex // https://github.com/retronym/scalac-survival-guide/blob/master/src/main/scala/guide/_19_ScalaSig.scala -// Jason warned me it may not be robust, but it seems to work fine for the specific purpose we have (i.e., +// Jason warned me it may not be robust, but it seems to work fine for the specific purpose we have (i.e., // checking if a top-level Class was created with Scala). object ScalaSig { private val ModuleClassName: Regex = """(.*)\$""".r diff --git a/testkit/javadsl/src/main/scala/com/lightbend/lagom/javadsl/testkit/ServiceTest.scala b/testkit/javadsl/src/main/scala/com/lightbend/lagom/javadsl/testkit/ServiceTest.scala index 19f6ead3a6..9a95b99dca 100644 --- a/testkit/javadsl/src/main/scala/com/lightbend/lagom/javadsl/testkit/ServiceTest.scala +++ b/testkit/javadsl/src/main/scala/com/lightbend/lagom/javadsl/testkit/ServiceTest.scala @@ -171,8 +171,8 @@ object ServiceTest { jdbc = false, cluster = false, configureBuilder = new JFunction[GuiceApplicationBuilder, GuiceApplicationBuilder] { - override def apply(b: GuiceApplicationBuilder): GuiceApplicationBuilder = b - } + override def apply(b: GuiceApplicationBuilder): GuiceApplicationBuilder = b + } ) override def withCassandra(enabled: Boolean): Setup = {