diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 92b4335e6..ac80d01df 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,15 +10,15 @@ jobs: env: JVM_OPTS: "-Xms1024m -Xmx1024m -XX:ReservedCodeCacheSize=128m -XX:MaxPermSize=256m -Dfile.encoding=UTF-8" steps: - - uses: actions/checkout@v7 - - uses: actions/setup-java@v5 - with: - distribution: zulu - java-version: 8 - cache: sbt - - uses: sbt/setup-sbt@v1 - - name: Test - run: | - sbt -v "^test" - sbt -v "^publishLocal" - sbt -v "it:test" + - uses: actions/checkout@v7 + - uses: actions/setup-java@v5 + with: + distribution: zulu + java-version: 8 + cache: sbt + - uses: sbt/setup-sbt@v1 + - name: Test + run: | + sbt -v "+test" + sbt -v "+publishLocal" + sbt -v "all support/IntegrationTest/test build/IntegrationTest/test" diff --git a/.gitignore b/.gitignore index 4f20d73e7..2f7703904 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,9 @@ target/ +target-* __pycache__/ docs/src/sphinx/version.py +.bsp +.devcontainer +.metals +.vscode +temp/ diff --git a/actorLogging/src/main/scala/com/typesafe/dbuild/logging/ActorLogging.scala b/actorLogging/src/main/scala/com/typesafe/dbuild/logging/ActorLogging.scala index ece5c7773..d1c6134ad 100644 --- a/actorLogging/src/main/scala/com/typesafe/dbuild/logging/ActorLogging.scala +++ b/actorLogging/src/main/scala/com/typesafe/dbuild/logging/ActorLogging.scala @@ -1,18 +1,11 @@ package com.typesafe.dbuild.logging import akka.actor.{ ActorRef, Actor, Props, PoisonPill, Terminated } -import sbt.{ - Level, - LogEvent, - Success, - Log, - Trace, - SetLevel, - SetTrace, - SetSuccess, - ControlEvent, - StackTrace -} +import sbt.io.IO +import sbt.io.Path._ +import sbt.io.syntax._ +import sbt.util.{ Level, LogEvent, Log, Trace, ControlEvent } +import sbt.internal.util.StackTrace /** A command to the logging system to log a given event into a particular path. */ case class LogCmd(path: String, evt: LogEvent, projName: String) @@ -29,16 +22,12 @@ import Level._ def success(msg: => String): Unit = sendLog(Level.Info, msg) def buffer[T](t: => T): T = t // TODO - buffer actor messages.... - def err(s: => String): Unit = - sendLog(Error, s) - def out(s: => String): Unit = - sendLog(Info, s) - def control(event: sbt.ControlEvent.Value, msg: => String): Unit = + def control(event: ControlEvent.Value, msg: => String): Unit = sendLogEvent(new ControlEvent(event, msg)) - def logAll(events: Seq[sbt.LogEvent]): Unit = { + def logAll(events: Seq[LogEvent]): Unit = { events foreach sendLogEvent } - def log(level: sbt.Level.Value, msg: => String): Unit = + def log(level: Level.Value, msg: => String): Unit = sendLog(level, msg) private def sendLog(level: Level.Value, msg: => String): Unit = sendLogEvent(new Log(level, msg)) @@ -84,13 +73,13 @@ trait LogToOutput { def log(lo: LogCmd): Unit = lo.evt match { case t: Trace => // TODO - Real trace levels... - writeLog(sbt.StackTrace.trimmed(t.exception, 1)) + writeLog(StackTrace.trimmed(t.exception, 1)) case l: Log if l.level >= level => val sb = new StringBuffer() for (line <- l.msg.split("""\n"""")) { // if projName, we are more interested in the project name, // rather than the error level (unless it is something other than "info") - if (lo.projName != "" && l.level == sbt.Level.Info) + if (lo.projName != "" && l.level == Level.Info) sb append ("[") append (lo.projName) append "] " else { sb append ("[") @@ -105,19 +94,18 @@ trait LogToOutput { } def writeLog(in: String): Unit - def level: sbt.Level.Value + def level: Level.Value } /** An actor that takes LogCmd messages and writes them to a file. */ class LoggerFileWriteActor(logDir: java.io.File, path: String) extends Actor with LogToOutput { - import sbt.Path._ def logFile = logDir / (ActorLogHelper.cleanPath(path) + ".log") def newWriter = { val f = logFile - sbt.IO touch f + IO touch f new java.io.FileWriter(f) } - var level: sbt.Level.Value = Level.Debug + var level: Level.Value = Level.Debug var output = newWriter override def postStop() = output.close() @@ -151,7 +139,6 @@ class LoggerFileWriteActor(logDir: java.io.File, path: String) extends Actor wit /** An actor that takes LogCmd messages and writes them to a file. */ class SystemOutLoggerActor(debug: Boolean) extends Actor with LogToOutput { -import sbt.Path._ val output = System.out val level = if (debug) Level.Debug else Level.Info diff --git a/actorProj/src/main/scala/com/typesafe/dbuild/project/build/BuildRunnerActor.scala b/actorProj/src/main/scala/com/typesafe/dbuild/project/build/BuildRunnerActor.scala index 8ef34c84c..9976e7e50 100644 --- a/actorProj/src/main/scala/com/typesafe/dbuild/project/build/BuildRunnerActor.scala +++ b/actorProj/src/main/scala/com/typesafe/dbuild/project/build/BuildRunnerActor.scala @@ -9,9 +9,10 @@ import scala.concurrent.duration._ import com.typesafe.dbuild.project.resolve.ProjectResolver import java.io.File import com.typesafe.dbuild.repo.core._ -import sbt.IO +import sbt.io.{ IO, DirectoryFilter } +import sbt.io.Path._ +import sbt.io.syntax._ import com.typesafe.dbuild.project.cleanup.Recycling._ -import sbt.Path._ import com.typesafe.dbuild.repo.core.GlobalDirs.buildDir import com.typesafe.dbuild.project.{ BuildSystem, BuildData } import com.typesafe.dbuild.utils.TrackedProcessBuilder @@ -25,7 +26,7 @@ case class RunBuild(build: RepeatableProjectBuild, outProjects: Seq[Project], ch class CleaningBuildActor extends Actor { def receive = { case target: File => - IO.delete(buildDir(target).*(sbt.DirectoryFilter).get.filter(markedForDeletion)) + IO.delete(buildDir(target).*(DirectoryFilter).get.filter(markedForDeletion)) self ! PoisonPill } } @@ -36,7 +37,7 @@ class BuildRunnerActor(builder: LocalBuildRunner, target: File, exp: CleanupExpi override def preStart() = { // Cleanup works in two stages; see ExtractorActor for details. // Note that cleanup is performed independently for the extraction and build directories - buildDir(target).*(sbt.DirectoryFilter).get.filter(upForDeletion(_, exp)).foreach(prepareForDeletion) + buildDir(target).*(DirectoryFilter).get.filter(upForDeletion(_, exp)).foreach(prepareForDeletion) // spawn the cleaning actor context.actorOf(Props(new CleaningBuildActor)) ! target } diff --git a/actorProj/src/main/scala/com/typesafe/dbuild/project/dependencies/ExtractorActor.scala b/actorProj/src/main/scala/com/typesafe/dbuild/project/dependencies/ExtractorActor.scala index 183844fd6..427922674 100644 --- a/actorProj/src/main/scala/com/typesafe/dbuild/project/dependencies/ExtractorActor.scala +++ b/actorProj/src/main/scala/com/typesafe/dbuild/project/dependencies/ExtractorActor.scala @@ -7,12 +7,13 @@ import scala.concurrent.Await import scala.concurrent.duration._ import com.typesafe.dbuild.model.{ ProjectBuildConfig, ExtractionConfig, ExtractionFailed, TimedOut } import _root_.java.io.File -import sbt.Path._ +import sbt.io.Path._ +import sbt.io.syntax._ import ExtractionDirs.projectExtractionDir import com.typesafe.dbuild.repo.core.GlobalDirs.extractionDir import com.typesafe.dbuild.model.CleanupExpirations import com.typesafe.dbuild.project.cleanup.Recycling._ -import sbt.{ IO, DirectoryFilter } +import sbt.io.{ IO, DirectoryFilter } import com.typesafe.dbuild.logging.Logger import Logger.prepareLogMsg import scala.util.{Success,Failure} diff --git a/adapter/src/main/scala-2.10/Adapter.scala b/adapter/src/main/scala-2.10/Adapter.scala index 80de5e827..26363db2a 100644 --- a/adapter/src/main/scala-2.10/Adapter.scala +++ b/adapter/src/main/scala-2.10/Adapter.scala @@ -15,7 +15,10 @@ object LoggingInterface { val Level = sbt.Level type Logger = sbt.Logger type LogEvent = sbt.LogEvent + type Log = sbt.Log + type Trace = sbt.Trace val ControlEvent = sbt.ControlEvent + type ControlEvent = sbt.ControlEvent val StackTrace = sbt.StackTrace type BasicLogger = sbt.BasicLogger } diff --git a/adapter/src/main/scala-2.12/Adapter.scala b/adapter/src/main/scala-2.12/Adapter.scala index a99502ad6..72ad97721 100644 --- a/adapter/src/main/scala-2.12/Adapter.scala +++ b/adapter/src/main/scala-2.12/Adapter.scala @@ -18,7 +18,10 @@ object LoggingInterface { val Level = sbt.util.Level type Logger = sbt.util.Logger type LogEvent = sbt.util.LogEvent + type Log = sbt.util.Log + type Trace = sbt.util.Trace val ControlEvent = sbt.util.ControlEvent + type ControlEvent = sbt.util.ControlEvent val StackTrace = sbt.internal.util.StackTrace type BasicLogger = sbt.internal.util.BasicLogger } diff --git a/build.sbt b/build.sbt index 0a5566a6e..b244b12aa 100644 --- a/build.sbt +++ b/build.sbt @@ -4,8 +4,10 @@ import SbtSupport._ def MyVersion: String = "0.9.20" +ThisBuild / scalaVersion := scala212 + // keep Maven Central happy -developers in ThisBuild := List( +ThisBuild / developers := List( Developer( id = "cunei", name = "Antonio Cunei", @@ -18,18 +20,18 @@ developers in ThisBuild := List( email = "seth.tisue@lightbend.com", url = url("https://www.lightbend.com") )) -homepage in ThisBuild := Some(url("http://lightbend-labs.github.io/dbuild/")) -scmInfo in ThisBuild := Some( +ThisBuild / homepage := Some(url("http://lightbend-labs.github.io/dbuild/")) +ThisBuild / scmInfo := Some( ScmInfo( url("https://github.com/lightbend-labs/dbuild"), "scm:git:git@github.com:lightbend-labs/dbuild.git") ) -sbtLaunchJarLocation in ThisBuild := (baseDirectory in ThisBuild).value / "target" / "sbt" / "sbt-launch.jar" +ThisBuild / sbtLaunchJarLocation := (ThisBuild / baseDirectory).value / "target" / "sbt" / "sbt-launch.jar" -sbtLaunchJar in ThisBuild := { - val cp = (externalDependencyClasspath in (sbtLauncher, Compile)).value - val location = (sbtLaunchJarLocation in ThisBuild).value +ThisBuild / sbtLaunchJar := { + val cp = (sbtLauncherProj / Compile / externalDependencyClasspath).value + val location = (ThisBuild / sbtLaunchJarLocation).value cp.map(_.data).find(_.getName.startsWith("sbt-launch")) match { case Some(x) => IO.copyFile(x, location) @@ -37,69 +39,75 @@ sbtLaunchJar in ThisBuild := { case None => sys.error("failed to resolve sbt-launch") } } +ThisBuild / organization := "com.typesafe.dbuild" +ThisBuild / licenses += License.Apache2 +ThisBuild / version := MyVersion +ThisBuild / resolvers += Resolver.typesafeIvyRepo("releases") +ThisBuild / resolvers += "Typesafe Repository" at "https://repo.typesafe.com/typesafe/releases/" -def SubProj(name: String) = ( - Project(name, file(if (name=="root") "." else name)) - configs( IntegrationTest ) - settings( Defaults.itSettings : _*) - settings( - version := MyVersion, - organization := "com.typesafe.dbuild", - selectScalaVersion, - resolvers += Resolver.typesafeIvyRepo("releases"), - resolvers += "Typesafe Repository" at "https://repo.typesafe.com/typesafe/releases/", - licenses += ("Apache-2.0", url("https://opensource.org/licenses/Apache-2.0")), - publishTo := sonatypePublishTo.value - ) - dependsOnRemote(specs2 _, jline) +def skip210 = Seq( + (compile / skip) := scalaVersion.value.startsWith("2.10"), + publish := Def.taskDyn { + val p = publish.taskValue + if (scalaVersion.value.startsWith("2.10")) Def.task {} else Def.task(p.value) + }.value, + publishLocal := Def.taskDyn { + val p = publishLocal.taskValue + if (scalaVersion.value.startsWith("2.10")) Def.task {} else Def.task(p.value) + }.value, + Compile / doc / sources := { + val theSources = (Compile / doc / sources).value + if ((compile / skip).value) List() else theSources + } ) -def skip212 = Seq( - skip in compile := scalaVersion.value.startsWith("2.12"), - publish := Def.taskDyn { - val p = publish.taskValue - if (scalaVersion.value.startsWith("2.12")) Def.task {} else Def.task(p.value) - }.value, - publishLocal := Def.taskDyn { - val p = publishLocal.taskValue - if (scalaVersion.value.startsWith("2.12")) Def.task {} else Def.task(p.value) - }.value, - sources in doc in Compile := - { - val theSources = (sources in doc in Compile).value - if((skip in compile).value) List() else theSources - } - ) +def crossBuildForPlugins = + crossScalaVersions := Vector(scala210, scala212) + +def selectSbtVersion = + (pluginCrossBuild / sbtVersion) := { + scalaBinaryVersion.value match { + case "2.10" => "0.13.18" + case "2.12" => "1.13.0" + case _ => "2.0.7" + } + } def selectScalaVersion = scalaVersion := { - val sb = (sbtVersion in pluginCrossBuild).value + val sb = (pluginCrossBuild / sbtVersion).value if (sb.startsWith("0.13")) "2.10.7" else "2.12.21" } -lazy val root = ( - SubProj("root") - aggregate(adapter, graph, hashing, logging, actorLogging, proj, actorProj, deploy, http, +lazy val root = (project in file(".")) + .dependsOnRemote(specs2 _, jline) + .aggregate(adapter, graph, hashing, logging, actorLogging, proj, actorProj, deploy, http, core, plugin, build, support, supportGit, repo, metadata, docs, dist, indexmeta) - settings(publish := Def.task {}, publishLocal := Def.task {}, version := MyVersion) - settings(crossSbtVersions := Seq("0.13.18", "1.2.1"), selectScalaVersion) -) + .settings( + publish / skip := true, + publishLocal / skip := true, + crossScalaVersions := Nil, + ) + .settings(crossSbtVersions := Seq("0.13.18", "1.13.0"), selectScalaVersion) // This subproject only has dynamically // generated source files, used to adapt // the source file to sbt 0.13/1.0 -lazy val adapter = ( - SubProj("adapter") - dependsOnSbtProvided(sbtLogging, sbtIo, dbuildLaunchInt, sbtIvy, sbtSbt) - dependsOnSbtProvidedOpt(zincIf212 _) - settings(sourceGenerators in Compile += task { - val dir = (sourceManaged in Compile).value - val fileName = "Default.scala" - val file = dir / fileName - val sv = scalaVersion.value - val v = (sbtVersion in pluginCrossBuild).value - if(!dir.isDirectory) dir.mkdirs() - IO.write(file, ( +lazy val adapter = project + .dependsOnRemote(specs2 _, jline) + .dependsOnSbtProvided(sbtLogging, sbtIo, sbtLauncherInt, sbtIvy, sbtSbt) + .dependsOnSbtProvidedOpt(zincIf212 _) + .settings( + crossBuildForPlugins, + selectSbtVersion, + Compile / sourceGenerators += task { + val dir = (Compile / sourceManaged).value + val fileName = "Default.scala" + val file = dir / fileName + val sv = scalaVersion.value + val v = (pluginCrossBuild / sbtVersion).value + if(!dir.isDirectory) dir.mkdirs() + IO.write(file, ( """ package com.typesafe.dbuild.adapter object Defaults { @@ -109,186 +117,242 @@ object Defaults { val scalaVersion = "%s" val sbtVersion = "%s" } -""" format (version.value, organization.value, scala.sys.process.Process("git log --pretty=format:%H -n 1").lines.head, sv, v)) +""" format (version.value, organization.value, + scala.sys.process.Process("git log --pretty=format:%H -n 1").lines.head, sv, v)) ) Seq(file) }) -) -lazy val graph = ( - SubProj("graph") -) +lazy val graph = project + .dependsOnRemote(specs2 _, jline) + .settings( + crossBuildForPlugins, + selectSbtVersion, + ) -lazy val hashing = ( - SubProj("hashing") - dependsOnRemote(typesafeConfig) -) +lazy val hashing = project + .dependsOnRemote(specs2 _, jline) + .dependsOnRemote(typesafeConfig) + .settings( + crossBuildForPlugins, + selectSbtVersion, + ) -lazy val indexmeta = ( - SubProj("indexmeta") -) +lazy val indexmeta = project + .dependsOnRemote(specs2 _, jline) + .settings( + crossBuildForPlugins, + selectSbtVersion, + ) -lazy val logging = ( - SubProj("logging") - dependsOn(adapter,graph) - dependsOnSbtProvided(sbtLogging, sbtIo, sbtCommand, dbuildLaunchInt) -) +lazy val logging = project + .dependsOnRemote(specs2 _, jline) + .dependsOn(adapter,graph) + .dependsOnSbtProvided(sbtLogging, sbtIo, sbtCommand, sbtLauncherInt) + .settings( + crossBuildForPlugins, + selectSbtVersion, + ) -lazy val actorLogging = ( - SubProj("actorLogging") - dependsOn(logging) - dependsOnRemote(akkaActor _) - dependsOnSbtProvided(sbtLogging, sbtIo, dbuildLaunchInt) - settings(skip212:_*) -) +lazy val actorLogging = project + .dependsOnRemote(specs2 _, jline) + .dependsOn(logging) + .dependsOnRemote(akkaActor _) + .dependsOnSbtProvided(sbtLogging, sbtIo, sbtLauncherInt) + .settings( + skip210, + selectSbtVersion, + ) -lazy val metadata = ( - SubProj("metadata") - dependsOn(graph, hashing, indexmeta, deploy) - dependsOnRemote(jackson, typesafeConfig, commonsLang, jacks) -) +lazy val metadata = project + .dependsOnRemote(specs2 _, jline) + .dependsOn(graph, hashing, indexmeta, deploy) + .dependsOnRemote(jackson, typesafeConfig, commonsLang, jacks) + .settings( + crossBuildForPlugins, + selectSbtVersion, + scalaXmlAlways, + ) -lazy val repo = ( - SubProj("repo") - dependsOn(http, adapter, metadata, logging) - dependsOnRemote(mvnAether, aether, aetherApi, aetherSpi, aetherUtil, aetherImpl, aetherConnectorBasic, aetherFile, aetherHttp, aetherWagon, mvnAether) - dependsOnSbtProvided(sbtIo, dbuildLaunchInt, sbtLogging, sbtSbt) -) +lazy val repo = project + .dependsOn(http, adapter, metadata, logging) + .dependsOnRemote(mvnAether, aether, aetherApi, aetherSpi, aetherUtil, aetherImpl, aetherConnectorBasic, aetherFile, aetherHttp, aetherWagon, mvnAether) + .dependsOnRemote(specs2 _, jline) + .dependsOnSbtProvided(sbtIo, sbtLauncherInt, sbtLogging, sbtSbt) + .settings( + crossBuildForPlugins, + selectSbtVersion, + scalaXmlAlways, + ) -lazy val http = ( - SubProj("http") - dependsOn(adapter) - dependsOnRemote(dispatch _) - dependsOnSbtProvided(sbtIo, sbtIvy, sbtSbt) -) +lazy val http = project + .dependsOn(adapter) + .dependsOnRemote(specs2 _, jline) + .dependsOnRemote(dispatch _) + .dependsOnSbtProvided(sbtIo, sbtIvy, sbtSbt) + .settings( + crossBuildForPlugins, + selectSbtVersion, + scalaXmlAlways, + ) -lazy val core = ( - SubProj("core") - dependsOnRemote(javaMail) - dependsOn(adapter,metadata, graph, hashing, logging, repo) - dependsOnSbtProvided(sbtIo, sbtLogging) -) +lazy val core = project + .dependsOnRemote(specs2 _, jline) + .dependsOnRemote(javaMail) + .dependsOn(adapter,metadata, graph, hashing, logging, repo) + .dependsOnSbtProvided(sbtIo, sbtLogging) + .settings( + crossBuildForPlugins, + selectSbtVersion, + scalaXmlAlways, + ) -lazy val proj = ( - SubProj("proj") - dependsOn(core, repo, logging) - dependsOnRemote(javaMail, commonsIO) - dependsOnSbtProvided(sbtIo, sbtIvy, sbtSbt, sbtLogging, dbuildLaunchInt) -) +lazy val proj = project + .dependsOnRemote(specs2 _, jline) + .dependsOn(core, repo, logging) + .dependsOnRemote(javaMail, commonsIO) + .dependsOnSbtProvided(sbtIo, sbtIvy, sbtSbt, sbtLogging, sbtLauncherInt) + .settings( + crossBuildForPlugins, + selectSbtVersion, + scalaXmlAlways, + ) -lazy val actorProj = ( - SubProj("actorProj") - dependsOn(core, actorLogging, proj) - dependsOnSbtProvided(sbtIo, sbtIvy) - settings(skip212:_*) -) +lazy val actorProj = project + .dependsOnRemote(specs2 _, jline) + .dependsOn(core, actorLogging, proj) + .dependsOnSbtProvided(sbtIo, sbtIvy) + .settings( + skip210, + selectSbtVersion, + scalaXmlAlways, + ) -lazy val support = ( - SubProj("support") - dependsOn(core, repo, metadata, proj % "compile->compile;it->compile", logging % "it") - dependsOnRemote(mvnEmbedder, mvnWagon, javaMail, aether, aetherApi, aetherSpi, aetherUtil, +lazy val support = project + .configs(IntegrationTest) + .dependsOn(core, repo, metadata, proj % "compile->compile;it->compile", logging % "it") + .dependsOnRemote(specs2 _, specs2It _, jline) + .dependsOnRemote(mvnEmbedder, mvnWagon, javaMail, aether, aetherApi, aetherSpi, aetherUtil, aetherImpl, aetherConnectorBasic, aetherFile, aetherHttp, slf4jSimple, ivy) - dependsOnSbtProvided(dbuildLaunchInt, sbtIvy) - dependsOnSbtProvidedIt(sbtSbt) - settings(SbtSupport.buildSettings:_*) - settings(SbtSupport.settings:_*) - settings( + .dependsOnSbtProvided(sbtLauncherInt, sbtIvy) + .dependsOnSbtProvidedIt(sbtSbt) + .settings(Defaults.itSettings) + .settings(SbtSupport.buildSettings:_*) + .settings(SbtSupport.settings:_*) + .settings( // We hook the testLoader of it to make sure all the it tasks have a legit sbt plugin to use. // Technically, this just pushes every project. We could outline just the plugin itself, but for now // we don't care that much. - testLoader in IntegrationTest := { + IntegrationTest / testLoader := { val ignore = publishLocal.all(ScopeFilter(inAggregates(LocalRootProject, includeRoot=false))).value - (testLoader in IntegrationTest).value + (IntegrationTest / testLoader).value }, - parallelExecution in IntegrationTest := false + IntegrationTest / parallelExecution := false, + crossBuildForPlugins, + selectSbtVersion, + scalaXmlAlways, ) -) // A separate support project for git/jgit -lazy val supportGit = ( - SubProj("supportGit") - dependsOn(core, repo, metadata, proj, support) - dependsOnRemote(mvnEmbedder, mvnWagon, javaMail, jgit) - dependsOnSbtProvided(dbuildLaunchInt, sbtIvy) - settings(skip212:_*) -) +lazy val supportGit = project + .dependsOnRemote(specs2 _, jline) + .dependsOn(core, repo, metadata, proj, support) + .dependsOnRemote(mvnEmbedder, mvnWagon, javaMail, jgit) + .dependsOnSbtProvided(sbtLauncherInt, sbtIvy) + .settings( + skip210, + selectSbtVersion, + scalaXmlAlways, + ) -// SBT plugin -lazy val plugin = ( - SubProj("plugin") - settings(sbtPlugin := true) - dependsOn(adapter, support, metadata) - dependsOnRemote(oro) - dependsOnSbtProvided(sbtIo) -) +// sbt plugin +lazy val plugin = project + .enablePlugins(SbtPlugin) + .dependsOnRemote(specs2 _, jline) + .dependsOn(adapter, support, metadata) + .dependsOnRemote(oro) + .dependsOnSbtProvided(sbtIo) + .settings( + crossBuildForPlugins, + selectSbtVersion, + scalaXmlAlways, + ) -lazy val dist = ( - SubProj("dist") - enablePlugins(UniversalPlugin) - settings(Packaging.settings(build,repo):_*) - settings(skip212:_*) -) +lazy val dist = (project in file("dist")) + .dependsOnRemote(specs2 _, jline) + .enablePlugins(UniversalPlugin) + .settings(Packaging.settings(build,repo):_*) + .settings( + skip210, + selectSbtVersion, + scalaXmlAlways, + ) -lazy val deploy = ( - SubProj("deploy") - dependsOn(adapter, http) - dependsOnRemote(jackson, typesafeConfig, commonsLang, aws, uriutil, commonsIO, jsch, jacks) - dependsOnSbtProvided(sbtLogging, sbtIo, sbtSbt) -) +lazy val deploy = project + .dependsOn(adapter, http) + .dependsOnRemote(specs2 _, jline) + .dependsOnRemote(jackson, typesafeConfig, commonsLang, aws, uriutil, commonsIO, jsch, jacks) + .dependsOnSbtProvided(sbtLogging, sbtIo, sbtSbt) + .settings( + crossBuildForPlugins, + selectSbtVersion, + scalaXmlAlways, + ) -lazy val build = ( - SubProj("build") - dependsOn(actorProj, support, supportGit, repo, metadata, deploy, proj) - dependsOnRemote(aws, uriutil, jsch, oro, scallop, commonsLang) - dependsOnRemote(gpgLibIf210 _) - dependsOnSbt(dbuildLaunchInt, sbtLogging, sbtIo, sbtIvy, sbtSbt, dbuildLauncher) - settings(skip212:_*) - settings(SbtSupport.settings:_*) - settings( +lazy val build = project + .dependsOnRemote(specs2 _, specs2It _, jline) + .configs(IntegrationTest) + .dependsOn(actorProj, support, supportGit, repo, metadata, deploy, proj) + .dependsOnRemote(aws, uriutil, jsch, oro, scallop, commonsLang) + .dependsOnRemote(gpgLibIf210 _) + .dependsOnSbt(sbtLauncherInt, sbtLogging, sbtIo, sbtIvy, sbtSbt) + .settings(Defaults.itSettings) + .settings( + skip210, + selectSbtVersion, + scalaXmlAlways, + SbtSupport.settings, // We hook the testLoader of it to make sure all the it tasks have a legit sbt plugin to use. // Technically, this just pushes every project. We could outline just the plugin itself, but for now // we don't care that much. - testLoader in IntegrationTest := { + IntegrationTest / testLoader := { val ignore = publishLocal.all(ScopeFilter(inAggregates(LocalRootProject, includeRoot=false))).value - (testLoader in IntegrationTest).value + (IntegrationTest / testLoader).value }, - parallelExecution in IntegrationTest := false + IntegrationTest / parallelExecution := false, + scalaXmlAlways, ) -) - -lazy val docs = ( - SubProj("docs") - enablePlugins(GhpagesPlugin, SphinxPlugin) - settings( - enableOutput in generatePdf in Sphinx := false, - enableOutput in generateEpub in Sphinx := false, +lazy val docs = project + .dependsOnRemote(specs2 _, jline) + .enablePlugins(GhpagesPlugin, SphinxPlugin) + .settings( + Sphinx / generatePdf / enableOutput := false, + Sphinx / generateEpub / enableOutput := false, git.remoteRepo := "git@github.com:lightbend/dbuild.git", ghpagesSynchLocal := { - val maps = (mappings in ghpagesSynchLocal).value + val maps = ((ghpagesSynchLocal / mappings)).value val repo = ghpagesUpdatedRepository.value val v = version.value val snap = isSnapshot.value val log = streams.value.log DocsSupport.synchLocalImpl(maps, repo, v, snap, log) }, - publish := (), - publishLocal := (), - skip in compile := true, + publish / skip := true, + publishLocal / skip := true, + compile / skip := true, makeSite := makeSite.dependsOn(sbt.Def.task { - val file = (siteSourceDirectory in Sphinx).value / "version.py" + val file = ((Sphinx / siteSourceDirectory)).value / "version.py" IO.write(file, ("release = '%s'\n" format (version.value))) }).value ) -) -lazy val sbtLauncher = ( - SubProj("sbt-launcher") - settings( +lazy val sbtLauncherProj = (project in file("sbt-launcher")) + .dependsOnRemote(specs2 _, jline) + .settings( autoScalaLibrary := false, - libraryDependencies += ("org.scala-sbt" % "sbt-launch" % "1.0.0").intransitive, - publish := (), - publishLocal := () + libraryDependencies += ("org.scala-sbt" % "sbt-launch" % "1.6.2").intransitive, + publish / skip := true, + publishLocal / skip := true, ) -) diff --git a/build/src/it/scala/com/typesafe/dbuild/build/RewireSpec.scala b/build/src/it/scala/com/typesafe/dbuild/build/RewireSpec.scala index 1245de9a9..561eb9baf 100644 --- a/build/src/it/scala/com/typesafe/dbuild/build/RewireSpec.scala +++ b/build/src/it/scala/com/typesafe/dbuild/build/RewireSpec.scala @@ -1,11 +1,5 @@ package com.typesafe.dbuild.build -// -// Warning: This test relies on the "build" module, that is currently only compiled -// for 0.12/2.9. Therefore, "^^0.12" must be issued before "build/it:test" or "it:test", -// otherwise this test might be inadvertently skipped. -// - import com.typesafe.dbuild.logging.{ConsoleLogger, Logger} import com.typesafe.dbuild.model._ import com.typesafe.dbuild.project.build.LocalBuildRunner @@ -15,6 +9,7 @@ import java.io.File import com.typesafe.config.ConfigFactory import com.typesafe.dbuild.model.Utils.readValueT import com.typesafe.dbuild.model.DBuildConfiguration +import com.typesafe.dbuild.support.sbt.Repositories // TDOO - Because this requires the sbt plugin to be published, we have to publsh locally // before we can run integration tests. @@ -28,8 +23,8 @@ object RewireSpec extends Specification { | check-missing: [false, false, false] | cross-version: standard | space: test - | sbt-version: "0.13.18" - | extraction-version: "2.11.1" + | sbt-version: "1.13.0" + | extraction-version: "2.12.21" | projects: [ | { | name: InjectionTest @@ -60,12 +55,10 @@ object RewireSpec extends Specification { "localIvy: file:"+System.getProperty("user.home")+"/.ivy2/local, [organization]/[module]/(scala_[scalaVersion]/)(sbt_[sbtVersion]/)[revision]/[type]s/[artifact](-[classifier]).[ext]", "sonatype-snapshots: https://oss.sonatype.org/content/repositories/snapshots", "sonatype-releases: https://oss.sonatype.org/content/repositories/releases", - "java-annoying-cla-shtuff: http://download.java.net/maven/2/", "typesafe-releases: https://repo.typesafe.com/typesafe/releases", "typesafe-ivy-releases: https://repo.typesafe.com/typesafe/ivy-releases, [organization]/[module]/(scala_[scalaVersion]/)(sbt_[sbtVersion]/)[revision]/[type]s/[artifact](-[classifier]).[ext]", "typesafe-ivy-snapshots: https://repo.typesafe.com/typesafe/ivy-snapshots, [organization]/[module]/(scala_[scalaVersion]/)(sbt_[sbtVersion]/)[revision]/[type]s/[artifact](-[classifier]).[ext]", "sbt-plugin-releases: https://repo.scala-sbt.org/scalasbt/sbt-plugin-releases, [organization]/[module]/(scala_[scalaVersion]/)(sbt_[sbtVersion]/)[revision]/[type]s/[artifact](-[classifier]).[ext]", - "jgit-repo: http://download.eclipse.org/jgit/maven", "scala-fresh-2.10.x: https://repo.typesafe.com/typesafe/scala-fresh-2.10.x/" ) val repoRecords = repoStrings map { @@ -75,12 +68,7 @@ object RewireSpec extends Specification { case z => sys.error("Internal error, unexpected split result: " + z) }} - val repos = { - val listMap = xsbt.boot.ListMap(repoRecords.toSeq.reverse: _*) - // getRepositories contains a ListMap.toList, where sbt's definition - // of toList is "backing.reverse". So we have to reverse again. - (new xsbt.boot.ConfigurationParser).getRepositories(listMap) - } + val repos = Repositories.parseRepositories(repoRecords) val main = new LocalBuildMain(repos, BuildRunOptions(CleanupOptions(), Timeouts(), true, true)) val outcome = try { diff --git a/build/src/main/scala/com/typesafe/dbuild/build/Checkout.scala b/build/src/main/scala/com/typesafe/dbuild/build/Checkout.scala index 6b67f5db2..0e98a6d35 100644 --- a/build/src/main/scala/com/typesafe/dbuild/build/Checkout.scala +++ b/build/src/main/scala/com/typesafe/dbuild/build/Checkout.scala @@ -7,12 +7,14 @@ import com.typesafe.dbuild.project.resolve.AggregateProjectResolver import com.typesafe.dbuild.logging.ConsoleLogger import com.typesafe.dbuild.project.build.LocalBuildRunner import com.typesafe.dbuild.utils.TrackedProcessBuilder -import sbt.Path._ +import sbt.io.Path._ +import sbt.io.syntax._ import sys.process._ import com.typesafe.dbuild.support.sbt.SbtBuildSystem import scala.collection.immutable.SortedMap import com.typesafe.dbuild.support.sbt.{ SbtRunner, SbtBuildConfig } import com.typesafe.dbuild.support.sbt.SbtRunner.SbtFileNames._ +import com.typesafe.dbuild.support.sbt.Repositories import com.typesafe.dbuild.logging.Logger import java.io.PrintWriter @@ -73,11 +75,7 @@ object Checkout { case z => sys.error("Internal error, unexpected split result: " + z) } } - // getRepositories contains a ListMap.toList, where sbt's definition - // of toList is "backing.reverse". So we have to reverse again, - // and we finally get the needed List[xsbti.Repository] - val listMap = xsbt.boot.ListMap(resolversMap.toSeq.reverse: _*) - val savedRepos = (new xsbt.boot.ConfigurationParser).getRepositories(listMap) + val savedRepos = Repositories.parseRepositories(resolversMap) val repos = if (useLocalResolvers || savedRepos.isEmpty) localRepos diff --git a/build/src/main/scala/com/typesafe/dbuild/build/Comparison.scala b/build/src/main/scala/com/typesafe/dbuild/build/Comparison.scala index 3944e2d3b..e032ea502 100644 --- a/build/src/main/scala/com/typesafe/dbuild/build/Comparison.scala +++ b/build/src/main/scala/com/typesafe/dbuild/build/Comparison.scala @@ -1,9 +1,7 @@ package com.typesafe.dbuild.build -import sbt._ -import com.typesafe.dbuild.adapter.Adapter -import Adapter.{IO,allPaths} -import Adapter.syntaxio._ +import sbt.io.{ IO, PathFinder } +import sbt.io.syntax._ import com.typesafe.dbuild.model._ import com.typesafe.dbuild.logging.Logger import java.io.File @@ -66,8 +64,8 @@ class Comparison(options: GeneralOptions, log: Logger) extends OptionTask(log) { if (badB.isEmpty) { val logLimit = 10 // excellent! We just need to compare the jars in dirA and dirB - val jarsA = dirA.**("*.jar").get - val jarsB = dirB.**("*.jar").get + val jarsA = PathFinder(dirA).allPaths.get.filter(_.getName.endsWith(".jar")) + val jarsB = PathFinder(dirB).allPaths.get.filter(_.getName.endsWith(".jar")) def checkPaths(x: Seq[String], y: Seq[String], xName: String, yName: String) = { val xNotY = x.diff(y) val ok = xNotY.isEmpty diff --git a/build/src/main/scala/com/typesafe/dbuild/build/DeployBuild.scala b/build/src/main/scala/com/typesafe/dbuild/build/DeployBuild.scala deleted file mode 100644 index 1933735a3..000000000 --- a/build/src/main/scala/com/typesafe/dbuild/build/DeployBuild.scala +++ /dev/null @@ -1,159 +0,0 @@ -package com.typesafe.dbuild.build - -import sbt._ -import com.typesafe.dbuild.adapter.Adapter -import Adapter.IO -import Adapter.syntaxio._ -import Adapter.allPaths -import com.typesafe.dbuild.model._ -import com.typesafe.dbuild.repo.core._ -import java.io.File -import java.net.URI -import com.amazonaws.services.s3.AmazonS3Client -import com.amazonaws.services.s3.model.PutObjectRequest -import com.amazonaws.auth.BasicAWSCredentials -import com.amazonaws.ClientConfiguration -import com.amazonaws.Protocol -import dispatch.classic.{ Logger => _, _ } -import com.jsuereth.pgp.{ PGP, SecretKey } -import org.bouncycastle.openpgp.{ PGPSecretKeyRingCollection, PGPSecretKeyRing } -import org.omg.PortableInterceptor.SUCCESSFUL -import com.typesafe.dbuild.logging.Logger.prepareLogMsg -import com.typesafe.dbuild.logging.Logger -import com.typesafe.dbuild.deploy.Creds.loadCreds -import com.jcraft.jsch.{ IO => sshIO, _ } -import java.util.Date -import com.jcraft.jsch.ChannelSftp -import com.typesafe.dbuild.deploy.Deploy - -class DeployBuild(options: GeneralOptions, log: Logger) extends OptionTask(log) { - import Deploy.isNotChecksum - def id = "Deploy" - def beforeBuild(projectNames: Seq[String]) = { - IO.withTemporaryDirectory { indexDir => - options.deploy foreach { d => - // just a sanity check on the project list (we don't use the result) - val _ = d.projects.flattenAndCheckProjectList(projectNames.toSet) - d.index foreach { indexOptions => - // sanity check, in case the supplied file name is something silly like "../xyz" or "/xyz/..." - val indexFile = new File(indexDir, indexOptions.filename).getCanonicalFile - if (!(indexFile.getCanonicalPath().startsWith(indexDir.getCanonicalPath()))) - sys.error("The specified file name \"" + indexOptions.filename + "\" is illegal, as it refers to a location outside the target URI") - } - } - } - checkDeployFullBuild(options.deploy) - } - def afterBuild(optRepBuild: Option[RepeatableDBuildConfig], outcome: BuildOutcome) = { - def dontRun() = log.error("*** Deploy cannot run: build did not complete.") - // we do not run deploy if we reached time out, or if we never arrived past extraction (or both) - if (outcome.isInstanceOf[TimedOut]) dontRun() else - optRepBuild match { - case None => dontRun - case Some(repBuild) => deployFullBuild(repBuild, outcome) - } - } - - // first, a proper sanity check - def checkDeployFullBuild(optionsSeq: Seq[DeployOptions]) = { - optionsSeq foreach { options => - val uri = new _root_.java.net.URI(options.uri) - uri.getScheme match { - case "file" | "null" => - if (options.credentials != None) log.warn("Credentials will be ignored while deploying to " + uri) - case "ssh" | "http" | "https" | "s3" => - options.credentials match { - case None => sys.error("Credentials are required when deploying to " + uri) - case Some(credsFile) => - if (loadCreds(credsFile).host != uri.getHost) - sys.error("The credentials file " + credsFile + " does not contain information for host " + uri.getHost) - } - case scheme => sys.error("Unknown scheme in deploy: " + scheme) - } - } - } - - /** - * The semantics of selection is: - * - For each node, the set of artifacts available for deploy is: the set of artifacts of all the - * successful children, plus its own if successful. - * - The root build, denoted by ".", has no artifacts of its own. - * - This rule also applies applies to nested hierarchical build systems, if they are in turn recursive. - */ - def deployFullBuild(build: RepeatableDBuildConfig, outcome: BuildOutcome) = { - val projectOutcomes = outcome.outcomes.map(o => (o.project, o)).toMap - // This does not contain the root ".", but we know that the root has no artifacts to be published of its own, - // therefore the set for "." is the union of those of the children, regardless if "." failed or not. - val optionsSeq = options.deploy - if (optionsSeq.nonEmpty) { - log.info("--== Deploying Artifacts ==--") - runRememberingExceptions(true, optionsSeq) { options => - log info ("Processing: " + options.uri) - // we need to retrieve the artifacts from the repository - // for build.uuid. We stage them in a temporary directory first, - // to make sure all is in order - val moduleInfos = try IO.withTemporaryDirectory { dir => - val (good, goodArts, goodModInfos, bad) = rematerialize(options.projects, outcome, build, dir, "deploy", - msgGood = "Deploying: ", - msgBad = "Cannot deploy: ", - partialOK = true, log) - - if (good.nonEmpty) try { - // Are we signing? If so, proceed - options.sign foreach { signOptions => - val secretRingFile = signOptions.secretRing map { new File(_) } getOrElse (GlobalDirs.userhome / ".gnupg" / "secring.gpg") - PGP.init - val passPhrase = { - val passPhraseFile = io.Source.fromFile(signOptions.passphrase) - val p = passPhraseFile.getLines.next - passPhraseFile.close() - p - } - val secretKey = signOptions.id match { - case Some(keyID) => - log.info("Signing with key: " + keyID) - new PGPSecretKeyRingCollection(new java.io.FileInputStream(secretRingFile)).getSecretKey(new java.math.BigInteger(keyID, 16).longValue) - case None => - log.info("Signing with default key...") - new PGPSecretKeyRing(new java.io.FileInputStream(secretRingFile)).getSecretKey - } - if (secretKey == null) sys.error("The key was not found in the pgp keyring.") - (allPaths(dir)).get.filter(f => !f.isDirectory && isNotChecksum(f.getName)) foreach { f => - SecretKey(secretKey).sign(f, new File(f.getAbsolutePath() + ".asc"), passPhrase.toArray) - } - } - // dir is staged; time to deploy - Deploy.deploy(target = options, dir, log) - } catch { - case e: NumberFormatException => - log.error("***ERROR*** Not a valid hexadecimal value: " + options.sign.get.id.get) - log.error("***ERROR*** Will not deploy.") - throw e - } - goodModInfos - } catch { - case e:Throwable => - log.error("***ERROR*** Encountered an error while deploying to " + options.uri) - throw e - } - - // We now need to prepare an index file, if requested - options.index foreach { indexOptions => - try IO.withTemporaryDirectory { indexDir => - val indexFile = new File(indexDir, indexOptions.filename).getCanonicalFile - val index = com.typesafe.dbuild.manifest.Index(moduleInfos.toSeq) - IO.write(indexFile, Utils.writeValue(index)) - Deploy.deploy(target = indexOptions, indexDir, log) - } - catch { - case e:Throwable => - log.error("***ERROR*** Encountered an error while generating or deploying the index file to " + indexOptions.uri) - throw e - } - } - - } - log.info("--== End Deploying Artifacts ==--") - } - } -} diff --git a/build/src/main/scala/com/typesafe/dbuild/build/Notifications.scala b/build/src/main/scala/com/typesafe/dbuild/build/Notifications.scala deleted file mode 100644 index e334169d9..000000000 --- a/build/src/main/scala/com/typesafe/dbuild/build/Notifications.scala +++ /dev/null @@ -1,325 +0,0 @@ -package com.typesafe.dbuild.build - -import com.typesafe.dbuild.model._ -import com.typesafe.dbuild.logging.Logger -import java.util.Properties -import java.util.Date -import javax.mail._ -import internet._ -import Message.RecipientType -import RecipientType._ -import com.typesafe.dbuild.deploy.Creds.loadCreds -import com.typesafe.dbuild.model.TemplateFormatter -import dispatch.classic.{ Logger => _, _ } -import com.typesafe.dbuild.model.SeqNotificationH._ -import com.typesafe.dbuild.model.SeqSelectorElementH._ -import com.typesafe.dbuild.model.SeqStringH._ - -// -// Ideally, the ConsoleNotification should become the mechanism by which the entire log of the -// dbuild compilation is printed on-screen: since builds can (will) work in parallel, the logs -// should be captured separately and printed at the end, one per project, via this mechanism -// rather than being mixed together while work progresses. -// -// Note: when implementing send(), only use templ.long, templ.short, and templ.summary (and templ.id for diagnostics only). -// Do not add any text to them, before or after: the entire text must be definable using the templates only. -class ConsoleNotificationContext(log: Logger) extends NotificationContext[ConsoleNotification] { - val defaultOptions = ConsoleNotification() - def mergeOptions(over: ConsoleNotification, under: ConsoleNotification) = defaultOptions - override def before() = { - log.info("--== Console Notifications ==--") - } - override def after() = { - log.info("--== Done Console Notifications ==--") - } - def send(n: ConsoleNotification, templ: TemplateFormatter, outcome: BuildOutcome) = { - templ.long.split("\n").foreach(log.info(_)) - None - } -} - -case class FlowdockJSON( - content: String, - external_user_name: String, - tags: Seq[String]) -case class FlowdockResponse( - message: Option[String]) -class FlowdockNotificationContext(log: Logger) extends NotificationContext[FlowdockNotification] { - val defaultOptions = FlowdockNotification(token = "", from = "") - def mergeOptions(over: FlowdockNotification, under: FlowdockNotification) = { - val newToken = if (over.token != defaultOptions.token) over.token else under.token - val newDetail = if (over.detail != defaultOptions.detail) over.detail else under.detail - val newFrom = if (over.from != defaultOptions.from) over.from else under.from - val newTags = if (over.tags != defaultOptions.tags) over.tags else under.tags - FlowdockNotification(token = newToken, detail = newDetail, from = newFrom, tags = newTags) - } - override def before() = { - log.info("--== Flowdock Notifications ==--") - } - override def after() = { - log.info("--== Done Flowdock Notifications ==--") - } - def send(n: FlowdockNotification, templ: TemplateFormatter, outcome: BuildOutcome) = { - def diag = " to Flowdock the outcome of project " + outcome.project + " using template " + templ.id - try { - def checkField(s: String, n: String) = - if (s == "") throw new RuntimeException("Field \"" + n + "\" MISSING (must be specified), when sending" + diag) - checkField(n.token, "token") - checkField(n.from, "from") - val token = (scala.io.Source.fromFile(n.token)).getLines.next - val msg = n.detail match { - case "summary" => templ.summary - case "short" => templ.short - case "long" => templ.long - case s => throw new RuntimeException("The Flowdock detail level must be one of: summary, short, long. (found: \"" + s + "\"") - } - val descriptor = new FlowdockJSON(content = msg, external_user_name = n.from, tags = n.tags) - val json = Utils.writeValue(descriptor) - val uri = "https://api.flowdock.com/v1/messages/chat/" + token - val sender = url(uri.toString).POST << (json, "application/json") - val response = (new Http with NoLogging)(sender >- { str => - Utils.readSomePath[FlowdockResponse](str) - }) - if (response != None && response.get.message != null && response.get.message != None) { - val out = response.get.message.get - log.error("While sending" + diag) - log.error("received the response: " + out) - } - None - } catch { - case mex: MessagingException => - log.error("ERROR SENDING" + diag) - throw mex - } - } -} - -class EmailNotificationContext(log: Logger) extends NotificationContext[EmailNotification] { - val defaultOptions = EmailNotification() - def mergeOptions(over: EmailNotification, under: EmailNotification) = { - val newTO = if (over.to != defaultOptions.to) over.to else under.to - val newCC = if (over.cc != defaultOptions.cc) over.cc else under.cc - val newBCC = if (over.bcc != defaultOptions.bcc) over.bcc else under.bcc - val newSMTP = if (over.smtp != defaultOptions.smtp) over.smtp else under.smtp - val newFROM = if (over.from != defaultOptions.from) over.from else under.from - EmailNotification(to = newTO, cc = newCC, bcc = newBCC, smtp = newSMTP, from = newFROM) - } - override def before() = { - log.info("--== Sending Email ==--") - } - override def after() = { - log.info("--== Done Sending Email ==--") - } - def send(n: EmailNotification, templ: TemplateFormatter, outcome: BuildOutcome) = { - import n._ - log.info("Sending outcome of project " + outcome.project + " to: " + ((to ++ cc ++ bcc).distinct.mkString(", "))) - val props = new Properties() - props.put("mail.smtp.host", smtp.server) - - smtp.encryption match { - case "ssl" => - if (!smtp.checkCertificate) - props.put("mail.smtp.ssl.checkserveridentity", "false"); - props.put("mail.smtp.ssl.trust", "*") - props.put("mail.smtp.ssl.enable", "true") - props.put("mail.smtp.port", "465") - case "starttls" => - if (!smtp.checkCertificate) - props.put("mail.smtp.starttls.checkserveridentity", "false"); - props.put("mail.smtp.starttls.enable", "true") - props.put("mail.smtp.starttls.required", "true"); - props.put("mail.smtp.port", "25") - case "submission" => - if (!smtp.checkCertificate) - props.put("mail.smtp.starttls.checkserveridentity", "false"); - props.put("mail.smtp.starttls.required", "true"); - props.put("mail.smtp.starttls.enable", "true") - props.put("mail.smtp.port", "587") - case "none" => - props.put("mail.smtp.port", "25") - case x => sys.error("Unknown authentication scheme: " + x) - } - if (!smtp.credentials.isEmpty) - props.put("mail.smtp.auth", "true") - - try { - val creds = smtp.credentials map { credFile => - val c = loadCreds(credFile) - if (c.host != smtp.server) - sys.error("The credentials file " + credFile + " does not contain information for host " + smtp.server) - c - } - val session = Session.getInstance(props, creds match { - case None => null - case Some(c) => - new javax.mail.Authenticator() { - protected override def getPasswordAuthentication(): javax.mail.PasswordAuthentication = { - return new PasswordAuthentication(c.user, c.pass) - } - } - }) - // session.setDebug(true) - val msg = new MimeMessage(session) - msg.setFrom(new InternetAddress({ - val userName = System.getProperty("user.name") - from match { - case Some(address) => address - case None => - val host = try { - java.net.InetAddress.getLocalHost().getHostName() - } catch { - // getLocalHost() will throw an exception if the current hostname is set but unrecognized - // by the local dns server. As a last resort, we fall back to "localhost". - case e:java.net.UnknownHostException => "localhost" - } - "dbuild at " + host + " <" + userName + "@" + host + ">" - } - }, /*strict checking*/ true): Address) - def setData(field: RecipientType, data: Seq[String]) = - msg.setRecipients(field, - data.map(new InternetAddress(_, true): Address).toArray) - setData(TO, to) - setData(CC, cc) - setData(BCC, bcc) - msg.setSubject(templ.short) - msg.setSentDate(new Date()) - msg.setText(templ.long + "\n") - // message is ready. Now, the delivery. - Transport.send(msg) - } catch { - case mex: MessagingException => - log.error("ERROR SENDING to " + n.to.mkString(", ") + " the outcome of project " + outcome.project + " using template " + templ.id) - throw mex - } - } -} - -// if doNotNotify is true, then ignore the selected notification options, and only print on the console (default) -class Notifications(defaultNotifications: Boolean, options: GeneralOptions, confName: String, log: Logger) extends OptionTask(log) { - def id = "Notifications" - val notificationOptions = if (defaultNotifications) NotificationOptions() else options.notifications - - val consoleCtx = new ConsoleNotificationContext(log) - val flowdockCtx = new FlowdockNotificationContext(log) - val emailCtx = new EmailNotificationContext(log) - val allContexts = Map("console" -> consoleCtx, "flowdock" -> flowdockCtx, "email" -> emailCtx) - def definedNotifications = notificationOptions.send - val usedNotificationKindIDs = definedNotifications.map { _.kind }.distinct - val defaultsMap = notificationOptions.default.map { d => (d.kind, d) }.toMap - val defDef = Notification(send = None) // defaults of defaults - - def beforeBuild(projectNames: Seq[String]) = { - val definedDefaults = notificationOptions.default - val defaultsKindIDs = definedDefaults.map { _.kind }.distinct - val unknown = (usedNotificationKindIDs ++ defaultsKindIDs).toSet -- allContexts.keySet - if (unknown.nonEmpty) { - sys.error(unknown.mkString("These notification kinds are unknown: ", ",", "")) - } - definedDefaults.groupBy(_.kind).foreach { kd => - if (kd._2.length > 1) { - sys.error("There can only be one default record for the kind: " + kd._1) - } - } - (notificationOptions.send ++ notificationOptions.default) foreach { n => - // just a sanity check on the project list (we don't use the result) - // flattenAndCheckProjectList() will check that the listed project names actually exist - val _ = n.projects.flattenAndCheckProjectList(projectNames.toSet) - } - } - - def afterBuild(repBuild: Option[RepeatableDBuildConfig], rootOutcome: BuildOutcome) = { - runRememberingExceptions(false, usedNotificationKindIDs) { kind => - allContexts(kind).before - sendNotifications(kind, rootOutcome) - allContexts(kind).after - } - } - - def sendNotifications(kind: String, rootOutcome: BuildOutcome) = { - val outcomes = rootOutcome.outcomes // children of the dbuild root - val userDefinedTemplates = notificationOptions.templates - val defnOpt = defaultsMap.get(kind) // defaults from the default records - - // scan the kinds for which at least one notification exists - runRememberingExceptions(false, definedNotifications.filter(kind == _.kind)) { n => - // Expansion from defaults; we do it manually. We must consider - // both the notification record, as well as the internals of the - // 'send' options; however, the latter are kind-specific, so we - // ask the corresponding NotificationContext to do it on our behalf. - // There are three stages: the initial standard values (defined in - // the source code), which appear if the fields are not specified - // in the JSON file. Then there are the notification defaults, - // specified in conf.options.notifications.defaults, and finally - // the topmost user record from conf.options.notifications.send. - // The last two have the first as their common default. - // The three have to be superimposed, and merged. - val combined = defnOpt match { - case None => n // no explicit default, pick n as-is - case Some(defn) => - val newWhen = if (n.when != defDef.when) n.when else defn.when - val newTempl = if (n.template != defDef.template) n.template else defn.template - val newProjects = if (n.projects != defDef.projects) n.projects else defn.projects - val newSend = allContexts(kind).mergeOptionsK(n.send, defn.send) - Notification(kind = kind, send = Some(newSend), when = newWhen, template = newTempl, projects = newProjects) - } - - def processOneNotification(n: Notification, outcome: BuildOutcome) = { - // we append the standard templates at the end, so that the user can override them - val resolvedTempl = n.resolveTemplate(userDefinedTemplates ++ standardTemplates) - if (outcome.whenIDs.intersect(n.when).nonEmpty) { - val formatter = new TemplateFormatter(resolvedTempl, outcome, confName) - allContexts(n.kind).notify(n.send, formatter, outcome) - } - } - // For notifications we do things a bit differently than in - // deploy. For deploy, we need to obtain a flattened list in - // order to retrieve the artifacts, and the root has no artifacts - // of its own. But, for notifications, there exists a report - // for the root that is distinct from those of the children. - // So we take the list literally: "." is really the report for - // the root (no expansion). - runRememberingExceptions(true, n.projects) { p => - val projectOutcomes = (rootOutcome +: outcomes).filter(_.project == p.name) - // due to the possible explicit target selection in the dbuild invocation, - // it may be that certain projects are listed in repeatableBuilds, but do not - // have a corresponding outcome. The check using flattenAndCheckProjectList(), - // above, should have already verified that all listed names exist, therefore - // if an outcome is missing do not stop, but just issue a notice. - if (projectOutcomes.isEmpty) - log.info("No outcome for project " + p.name + " (skipped)") - else { - if (projectOutcomes.length > 1) - sys.error("Internal error: multiple outcomes detected for project " + p.name + ". Please report.") - processOneNotification(combined, projectOutcomes.head) - } - } - } - } - - val standardTemplates = Seq( - NotificationTemplate("console", - "${dbuild.template-vars.padded-project-description}: ${dbuild.template-vars.status}", - None, - Some("""---== Execution Report ==--- -Report from the dbuild run for ${dbuild.template-vars.project-description}: -${dbuild.template-vars.subprojects-report}>>> ${dbuild.template-vars.padded-project-description}: ${dbuild.template-vars.status} ----== End Execution Report ==---""")), - NotificationTemplate("flowdock", - "${JOB_NAME} on ${NODE_NAME}: ${dbuild.template-vars.status}", - Some("""${JOB_NAME} on ${NODE_NAME}: ${dbuild.template-vars.status} -Info at: ${BUILD_URL}console"""), - Some("""${JOB_NAME} on ${NODE_NAME}: ${dbuild.template-vars.status} -${dbuild.template-vars.subprojects-report-tabs}Info at: ${BUILD_URL}console""")), - NotificationTemplate("email", - "[${JOB_NAME}] ${dbuild.template-vars.project-description}: ${dbuild.template-vars.status}", - None, - Some("""This is a report for ${dbuild.template-vars.project-description} in the configuration "${dbuild.template-vars.config-name}" -running under the Jenkins job "${JOB_NAME}" on ${NODE_NAME}. - -${dbuild.template-vars.subprojects-report}>>> ${dbuild.template-vars.padded-project-description}: ${dbuild.template-vars.status} - - -A more detailed report is available at: -${BUILD_URL}console -"""))) -} diff --git a/build/src/main/scala/com/typesafe/dbuild/build/SbtBuildMain.scala b/build/src/main/scala/com/typesafe/dbuild/build/SbtBuildMain.scala index 345c2ec48..09157a6ca 100644 --- a/build/src/main/scala/com/typesafe/dbuild/build/SbtBuildMain.scala +++ b/build/src/main/scala/com/typesafe/dbuild/build/SbtBuildMain.scala @@ -16,6 +16,7 @@ import com.typesafe.dbuild.utils.Time.timed import com.typesafe.dbuild.utils.TrackedProcessBuilder import collection.immutable.SortedMap import com.typesafe.dbuild.adapter.Defaults +import com.typesafe.dbuild.support.sbt.Repositories import com.typesafe.config.{ ConfigSyntax, ConfigFactory, ConfigParseOptions } import org.rogach.scallop._ import org.rogach.scallop.exceptions.ScallopException @@ -224,10 +225,7 @@ class SbtBuildMain extends xsbti.AppMain { val repos = if (useLocalResolvers || resolvers.isEmpty) localRepos else { - // getRepositories contains a ListMap.toList, where sbt's definition - // of toList is "backing.reverse". So we have to reverse again. - val listMap = xsbt.boot.ListMap(resolvers.toSeq.reverse: _*) - (new xsbt.boot.ConfigurationParser).getRepositories(listMap) + Repositories.parseRepositories(resolvers) } if (debug) { println("Resolvers:") diff --git a/build/src/main/scala/com/typesafe/dbuild/build/SimpleBuildActor.scala b/build/src/main/scala/com/typesafe/dbuild/build/SimpleBuildActor.scala index 05a64404b..0bdd631da 100644 --- a/build/src/main/scala/com/typesafe/dbuild/build/SimpleBuildActor.scala +++ b/build/src/main/scala/com/typesafe/dbuild/build/SimpleBuildActor.scala @@ -17,7 +17,6 @@ import scala.concurrent.duration._ import scala.concurrent.{ Future, Promise, ExecutionContext } import ExecutionContext.Implicits.global import akka.util.Timeout -import sbt.Path._ import java.io.File import com.typesafe.dbuild.repo.core.GlobalDirs import org.apache.maven.execution.BuildFailure @@ -55,9 +54,7 @@ class SimpleBuildActor(extractor: ActorRef, builder: ActorRef, repository: Repos // After this point, inputConf and its BuildOptions are never used again. // val result = try { - val notifTask = new Notifications(options.defaultNotifications, generalOptions, confName, log) - // add further new tasks at the beginning of this list, leave notifications at the end - val tasks: Seq[OptionTask] = Seq(new DeployBuild(generalOptions, log), new Comparison(generalOptions, log), notifTask) + val tasks: Seq[OptionTask] = Seq(new Comparison(generalOptions, log)) val projectNames = projects.map { _.name } tasks foreach { _.beforeBuild(projectNames) } // afterTasks may be called when the build is complete, or when something went wrong. @@ -74,32 +71,14 @@ class SimpleBuildActor(extractor: ActorRef, builder: ActorRef, repository: Repos if (tasks.nonEmpty) futureBuildResult map { // >>>> careful with map() on Futures: exceptions must be caught separately!! wrapExceptionIntoOutcome[BuildOutcome](".", log) { buildOutcome => - val taskOuts = { - val taskOutsWithoutNotif = tasks.diff(Seq(notifTask)) map { t => - try { // even if one task fails, we move on to the rest - t.afterBuild(rdb, buildOutcome) - (t.id, true) - } catch { - case e:Throwable => - (t.id, false) - } - } - // generate an outcome that Notifications can use, with a report from all other tasks - val badForNotif = taskOutsWithoutNotif.filter(!_._2).map { _._1 } - val outcomeForNotif = if (badForNotif.nonEmpty) - TaskFailed(".", buildOutcome.outcomes, buildOutcome, "Tasks failed: " + badForNotif.mkString(", ")) - else - buildOutcome - // ok, let's concatenate the previous task results with the one from notifications, and proceed with the - // calculation of the final global outcome and the final tasks reporting (and possibly an emergency notification, - // if that is ever implemented). - taskOutsWithoutNotif :+ (try { - notifTask.afterBuild(rdb, outcomeForNotif) - (notifTask.id, true) + val taskOuts = tasks map { t => + try { // even if one task fails, we move on to the rest + t.afterBuild(rdb, buildOutcome) + (t.id, true) } catch { case e:Throwable => - (notifTask.id, false) - }) + (t.id, false) + } } log.info("---== Tasks Report ==---") val (good, bad) = taskOuts.partition(_._2) diff --git a/deploy/src/main/scala/com/typesafe/dbuild/deploy/Deploy.scala b/deploy/src/main/scala/com/typesafe/dbuild/deploy/Deploy.scala index 72310fc54..458bc2983 100644 --- a/deploy/src/main/scala/com/typesafe/dbuild/deploy/Deploy.scala +++ b/deploy/src/main/scala/com/typesafe/dbuild/deploy/Deploy.scala @@ -8,7 +8,6 @@ import com.amazonaws.services.s3.model.PutObjectRequest import com.amazonaws.auth.BasicAWSCredentials import com.amazonaws.ClientConfiguration import com.amazonaws.Protocol -import org.omg.PortableInterceptor.SUCCESSFUL import Creds.loadCreds import com.jcraft.jsch.{ IO => sshIO, Logger => _, _ } import java.util.Date diff --git a/project/DbuildLauncher.scala b/project/DbuildLauncher.scala index 011c80d52..dd37bc06a 100644 --- a/project/DbuildLauncher.scala +++ b/project/DbuildLauncher.scala @@ -2,7 +2,6 @@ import sbt._ object DbuildLauncher { val launcherVersion = "1.0.1-d1" - val launchInt = "com.typesafe.dbuild" % "launcher-interface" % launcherVersion val launcher = "com.typesafe.dbuild" % "launcher" % launcherVersion val uri = "https://dl.cloudsmith.io/public/lightbend/maven-releases/maven/com/typesafe/dbuild/launcher/" + launcherVersion + "/launcher-" + launcherVersion+".jar" diff --git a/project/Dependencies.scala b/project/Dependencies.scala index d00a3d532..eced445ba 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -1,8 +1,10 @@ -import sbt._ -import DbuildLauncher._ +import sbt.* +import Keys.* object Dependencies { + val scala210 = "2.10.7" + val scala212 = "2.12.21" val mvnVersion = "3.5.2" val typesafeConfig = "com.typesafe" % "config" % "1.2.1" @@ -52,9 +54,15 @@ object Dependencies { def specs2(scala212: Boolean) = if (scala212) - "org.specs2" %% "specs2-core" % "3.8.8" % "it,test" + "org.specs2" %% "specs2-core" % "3.8.8" % "test" else - "org.specs2" %% "specs2" % "2.1.1" % "it,test" + "org.specs2" %% "specs2" % "2.1.1" % "test" + + def specs2It(scala212: Boolean) = + if (scala212) + "org.specs2" %% "specs2-core" % "3.8.8" % "it" + else + "org.specs2" %% "specs2" % "2.1.1" % "it" def dispatch(scala212: Boolean) = if (scala212) @@ -95,16 +103,7 @@ object Dependencies { else "org.scala-sbt" % "sbt" % v - // We deal with two separate launchers: - // 1) The "sbt-launch.jar" is the regular sbt launcher. we package it in the "build" subproject - // as a resource, so that it is available to the running dbuild when it wants to spawn a further sbt. - // 2) We use a modified, dbuild-specific modified version in order to launch dbuild. This - // is necessary since the Proguard-optimized sbt launcher is unusable as a library. This is the - // version herebelow. The dependencies are not always provided, so we handle them like sbt dependencies, - // even though they do not really change on scalaversion/sbtversion - - def dbuildLaunchInt(scala212: Boolean, v:String) = launchInt - def dbuildLauncher(scala212: Boolean, v:String) = launcher + def sbtLauncherInt(scala212: Boolean, v:String) = "org.scala-sbt" % "launcher-interface" % "1.6.2" // other dependencies that depend on whether scala is 2.10 or 2.12, but are only included in some cases def zincIf212(scala212: Boolean, v:String): Option[ModuleID] = @@ -119,4 +118,6 @@ object Dependencies { else Some("com.jsuereth" %% "gpg-library" % "0.8.2") + def scalaXmlAlways = + libraryDependencySchemes += "org.scala-lang.modules" %% "scala-xml" % VersionScheme.Always } diff --git a/project/RemoteDepHelper.scala b/project/RemoteDepHelper.scala index 764429135..3f6051569 100644 --- a/project/RemoteDepHelper.scala +++ b/project/RemoteDepHelper.scala @@ -23,7 +23,7 @@ class RemoteDepHelper(p: Project) { def dependsOnSbtProvided(ms: SbtDep*): Project = dependsOnSbtP(true, false, ms:_*) def dependsOnSbtProvidedOpt(fms: (Boolean, String) => Option[sbt.ModuleID]): Project = { p.settings(libraryDependencies ++= { - fms(scalaVersion.value.startsWith("2.12"), (sbtVersion in pluginCrossBuild).value) map { d => + fms(scalaVersion.value.startsWith("2.12"), ((pluginCrossBuild / sbtVersion)).value) map { d => d % "provided" } }.toSeq) @@ -31,13 +31,19 @@ class RemoteDepHelper(p: Project) { def dependsOnSbtProvidedIt(ms: SbtDep*): Project = dependsOnSbtP(true, true, ms:_*) def dependsOnSbtP(provided: Boolean, itOnly: Boolean, ms: SbtDep*): Project = p.settings(libraryDependencies ++= { - val v = (sbtVersion in pluginCrossBuild).value + val v = ((pluginCrossBuild / sbtVersion)).value val scala212 = scalaVersion.value.startsWith("2.12") - ms map { lib => + val cs = ivyConfigurations.value + ms.flatMap { lib => val d = lib(scala212, v) - if (itOnly && !provided) (d % "it") else - if (provided && !itOnly) (d % "provided") else - if (provided && itOnly) (d % "it,provided") else d + if (itOnly && !provided) + if (cs.contains(IntegrationTest)) Some(d % "it") + else None + else if (provided && !itOnly) Some(d % "provided") + else if (provided && itOnly) + if (cs.contains(IntegrationTest)) Some(d % "it,provided") + else Some(d % "provided") + else Some(d) } }) } diff --git a/project/SbtSupport.scala b/project/SbtSupport.scala index dd893ab2e..ddc180cf5 100644 --- a/project/SbtSupport.scala +++ b/project/SbtSupport.scala @@ -9,6 +9,6 @@ object SbtSupport { val buildSettings: Seq[Setting[_]] = Nil val settings: Seq[Setting[_]] = buildSettings ++ Seq( // The jar is added as a resource, so that the running dbuild can find it and use it to spawn new instances of sbt - resourceGenerators in Compile += sbtLaunchJar.taskValue + (Compile / resourceGenerators) += sbtLaunchJar.taskValue ) } diff --git a/project/build.properties b/project/build.properties index 8e682c526..e0a1aa023 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=0.13.18 +sbt.version=1.13.0 diff --git a/project/build.sbt b/project/build.sbt deleted file mode 100644 index a061e5a4b..000000000 --- a/project/build.sbt +++ /dev/null @@ -1,14 +0,0 @@ -addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.3.2") -addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "2.3") -addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.1.2-1") - -libraryDependencies ++= { - val dependencies = Seq( - "com.typesafe.sbt" % "sbt-site" % "1.3.1", - "com.typesafe.sbt" % "sbt-ghpages" % "0.6.2", - "com.typesafe.sbt" % "sbt-s3" % "0.9") - val sbtV = (sbtBinaryVersion in update).value - val scalaV = (scalaBinaryVersion in update).value - if (scalaV.startsWith("2.10")) - dependencies map { sbt.Defaults.sbtPluginExtra(_, sbtV, scalaV) } else Seq.empty -} diff --git a/project/docs.scala b/project/docs.scala index ea69483bf..3ae75fe99 100644 --- a/project/docs.scala +++ b/project/docs.scala @@ -1,4 +1,4 @@ -import sbt.Path.richFile +import sbt.* import sbt.Keys._ import sbt.Path._ import sbt.Def @@ -6,6 +6,7 @@ import sbt.IO import sbt.Logger import java.io.File import sbt.{Setting,PatternFilter,DirectoryFilter} + /* import com.typesafe.sbt.SbtSite.site import com.typesafe.sbt.SbtGhPages.{ghpages, GhPagesKeys} diff --git a/project/http.sbt b/project/http.sbt deleted file mode 100644 index b71cd0b01..000000000 --- a/project/http.sbt +++ /dev/null @@ -1,2 +0,0 @@ -// This is a bit circular, indeed. But why not? -libraryDependencies += "com.typesafe.dbuild" %% "http" % "0.9.9" diff --git a/project/packaging.scala b/project/packaging.scala index 1f02d49cb..8e2556298 100644 --- a/project/packaging.scala +++ b/project/packaging.scala @@ -12,8 +12,11 @@ object Packaging { def mapArt[A](key:sbt.TaskKey[_], kind: String) = // cheat a little: by setting the classifier to the version number, we can // publish to Ivy the tgz/zip with the full name, like "dbuild-0.8.1.tgz". - artifact in (Universal, key) := - (artifact in (Universal, key)).value.copy(`type` = kind, extension = kind, `classifier` = Some(version.value)) + Universal / key / artifact := + (Universal / key / artifact).value + .withType(kind) + .withExtension(kind) + .withClassifier(Some(version.value)) def settings(build:Project, repo:Project): Seq[Setting[_]] = SbtSupport.buildSettings ++ Seq( @@ -22,7 +25,7 @@ object Packaging { maintainer := "Antonio Cunei ", packageSummary := "Multi-project builder.", packageDescription := """A multi-project builder capable of glueing together a set of related projects.""", - name in Universal := name.value + "-" + version.value, + Universal / name := name.value + "-" + version.value, rpmRelease := "1", rpmVendor := "typesafe", rpmUrl := Some("https://github.com/lightbend/dbuild"), @@ -32,7 +35,7 @@ object Packaging { // otherwise Universal may end up using outdated files. // The command "release" in root will perform a clean, followed by a publish. - publishArtifact in Compile := false, + Compile / publishArtifact := false, // NB: A clean must be executed before both packageZipTarball and packageZipTarball, // otherwise Universal may end up using outdated files. @@ -52,12 +55,12 @@ object Packaging { crossPaths := false ) ++ - addArtifact(artifact in (Universal, packageZipTarball), packageZipTarball in Universal) ++ - addArtifact(artifact in (Universal, packageBin), packageBin in Universal) ++ - Seq(mappings in Universal ++= Seq( - Packaging.makeDBuildProps(target.value, sourceDirectory.value, (scalaVersion in build).value, (version in build).value), - Packaging.makeDRepoProps(target.value, sourceDirectory.value, (scalaVersion in build).value, (version in build).value), - Packaging.dbuildLauncher(target.value, streams.value.log, (version in build).value) + addArtifact(Universal / packageZipTarball / artifact, Universal / packageZipTarball) ++ + addArtifact(Universal / packageBin / artifact, Universal / packageBin) ++ + Seq((Universal / mappings) ++= Seq( + Packaging.makeDBuildProps(target.value, sourceDirectory.value, ((build / scalaVersion)).value, ((build / version)).value), + Packaging.makeDRepoProps(target.value, sourceDirectory.value, ((build / scalaVersion)).value, ((build / version)).value), + Packaging.dbuildLauncher(target.value, streams.value.log, ((build / version)).value) ) ) diff --git a/project/plugins.sbt b/project/plugins.sbt new file mode 100644 index 000000000..deb73d356 --- /dev/null +++ b/project/plugins.sbt @@ -0,0 +1,7 @@ +addSbtPlugin("com.github.sbt" % "sbt-native-packager" % "1.11.7") +addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.3.2") +addSbtPlugin("com.github.sbt" % "sbt-site" % "1.6.0") +addSbtPlugin("com.github.sbt" % "sbt-site-sphinx" % "1.6.0") +addSbtPlugin("com.github.sbt" % "sbt-ghpages" % "0.10.0") +addSbtPlugin("cf.janga" % "sbts3" % "0.10.5") +libraryDependencySchemes += "org.scala-lang.modules" %% "scala-xml" % VersionScheme.Always diff --git a/support/src/it/scala/com/typesafe/dbuild/support/sbt/SbtTestHarness.scala b/support/src/it/scala/com/typesafe/dbuild/support/sbt/SbtTestHarness.scala index fceacdf65..45e0168f1 100644 --- a/support/src/it/scala/com/typesafe/dbuild/support/sbt/SbtTestHarness.scala +++ b/support/src/it/scala/com/typesafe/dbuild/support/sbt/SbtTestHarness.scala @@ -14,9 +14,14 @@ object SbtTestHarness { artifactPattern: String = defaultIvyPatterns, mavenCompatible: Boolean = false, descriptorOptional: Boolean = false, - skipConsistencyCheck:Boolean = false + skipConsistencyCheck: Boolean = false, + allowInsecureProtocol: Boolean = false ) extends xsbti.IvyRepository - private case class MvnRepo(id: String, url: URL) extends xsbti.MavenRepository + private case class MvnRepo( + id: String, + url: URL, + allowInsecureProtocol: Boolean = false + ) extends xsbti.MavenRepository // TODO - we should pull in whatever local ~/.sbt/repositories specifies, or what the current sbt project is using, // so we dont' have super slow integration tests. private val fallBackResolvers: List[xsbti.Repository] = diff --git a/support/src/main/scala/com/typesafe/dbuild/support/sbt/Repositories.scala b/support/src/main/scala/com/typesafe/dbuild/support/sbt/Repositories.scala index 77f84c5e2..477e9eac2 100644 --- a/support/src/main/scala/com/typesafe/dbuild/support/sbt/Repositories.scala +++ b/support/src/main/scala/com/typesafe/dbuild/support/sbt/Repositories.scala @@ -2,11 +2,11 @@ package com.typesafe.dbuild.support.sbt import com.typesafe.dbuild.model._ import _root_.java.io.File -import _root_.java.net.URI +import _root_.java.net.{ URI, URL } import com.typesafe.dbuild.adapter.Adapter.IO object Repositories { - val ivyPattern = "[organization]/[module]/(scala_[scalaVersion]/)(sbt_[sbtVersion]/)[revision]/[type]s/[artifact](-[classifier]).[ext]" + val ivyPattern = "[organization]/[module]/(scala_[scalaVersion]/)(sbt_[sbtVersion]/)[revision]/[type]s/[artifact](-[classifier]).[ext]" def writeRepoFile(repos:List[xsbti.Repository], config: File, repositories: (String, String)*): Unit = { val sb = new StringBuilder("[repositories]\n") for((name, uri) <- repositories) { @@ -19,5 +19,28 @@ object Repositories { case p:xsbti.PredefinedRepository => sb append (" "+p.id+"\n") } IO.write(config, sb.toString) - } + } + + private case class PredefRepo(id: xsbti.Predefined) extends xsbti.PredefinedRepository + private case class MvnRepo(id: String, url: URL, allowInsecureProtocol: Boolean = false) extends xsbti.MavenRepository + private case class IvyRepo(id: String, url: URL, ivyPattern: String, artifactPattern: String, + mavenCompatible: Boolean = false, descriptorOptional: Boolean = false, + skipConsistencyCheck: Boolean = false, allowInsecureProtocol: Boolean = false) extends xsbti.IvyRepository + + /** + * Parses the same (id -> spec) shape that writeRepoFile()'s "[repositories]" entries + * encode: `id -> None` for a predefined repository (matched against xsbti.Predefined's + * labels, e.g. "local", "maven-central"), `id -> Some("url")` for a Maven repository, and + * `id -> Some("url, ivyPattern")` for an Ivy repository. + */ + def parseRepositories(entries: Iterable[(String, Option[String])]): List[xsbti.Repository] = + entries.map { + case (id, None) => PredefRepo(xsbti.Predefined.toValue(id)) + case (id, Some(spec)) => + spec.split(",", 2).map(_.trim) match { + case Array(url) => MvnRepo(id, new URL(url)) + case Array(url, pattern) => IvyRepo(id, new URL(url), pattern, pattern) + case z => sys.error("Internal error, unexpected split result: " + z.mkString(",")) + } + }.toList } diff --git a/support/src/main/scala/com/typesafe/dbuild/support/sbt/SbtRunner.scala b/support/src/main/scala/com/typesafe/dbuild/support/sbt/SbtRunner.scala index 7256030c4..3fb948d37 100644 --- a/support/src/main/scala/com/typesafe/dbuild/support/sbt/SbtRunner.scala +++ b/support/src/main/scala/com/typesafe/dbuild/support/sbt/SbtRunner.scala @@ -124,12 +124,9 @@ class SbtRunner(repos: List[xsbti.Repository], globalBase: File, debug: Boolean) object SbtRunner { // TODO - Configure these somewhere? val defaultJavaArgs = Seq( - "-XX:+CMSClassUnloadingEnabled", - "-XX:+DoEscapeAnalysis", "-Xms1536m", "-Xmx1536m", "-Xss2m", - "-XX:MaxPermSize=640m", "-XX:ReservedCodeCacheSize=192m" ) diff --git a/supportGit/src/main/scala/com/typesafe/dbuild/support/git/ProjectResolver.scala b/supportGit/src/main/scala/com/typesafe/dbuild/support/git/ProjectResolver.scala index b01e96a51..d97ba17a5 100644 --- a/supportGit/src/main/scala/com/typesafe/dbuild/support/git/ProjectResolver.scala +++ b/supportGit/src/main/scala/com/typesafe/dbuild/support/git/ProjectResolver.scala @@ -1,6 +1,7 @@ package com.typesafe.dbuild.support.git -import _root_.sbt.Path._ +import sbt.io.Path._ +import sbt.io.syntax._ import com.typesafe.dbuild.model._ import com.typesafe.dbuild.project.resolve.ProjectResolver import com.typesafe.dbuild.logging.Logger