diff --git a/appveyor.yml b/appveyor.yml index 5b5c15d3d..26ee8e212 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -3,8 +3,8 @@ version: '{build}' os: Windows Server 2012 install: - cmd: mkdir C:\sbt - - cmd: curl -Lo C:\sbt\sbt https://github.com/coursier/sbt-launcher/releases/download/v1.2.17/csbt - - cmd: curl -Lo C:\sbt\sbt.bat https://github.com/coursier/sbt-launcher/releases/download/v1.2.17/csbt.bat + - cmd: curl -Lo C:\sbt\sbt https://github.com/coursier/sbt-launcher/releases/download/v1.2.20/csbt + - cmd: curl -Lo C:\sbt\sbt.bat https://github.com/coursier/sbt-launcher/releases/download/v1.2.20/csbt.bat - cmd: SET JAVA_HOME=C:\Program Files\Java\jdk1.8.0 - cmd: SET PATH=C:\sbt;%JAVA_HOME%\bin;%PATH% - cmd: SET JAVA_OPTS=-Xmx4g -Xss2m @@ -19,7 +19,7 @@ build_script: - cmd: .\metadata\coursier fetch io.get-coursier:http-server_2.12:1.0.0 - ps: Start-Job -filepath .\metadata\scripts\start-it-auth-server.ps1 -ArgumentList $pwd\metadata, $env:TEST_REPOSITORY_HOST, $env:TEST_REPOSITORY_PORT, $env:TEST_REPOSITORY_USER, $env:TEST_REPOSITORY_PASSWORD test_script: - - sbt ++2.12.7 "sbt-lm-coursier/scripted shared-2/simple" sbt-coursier/scripted + - sbt ++2.12.11 "sbt-lm-coursier/scripted shared-2/simple" sbt-coursier/scripted branches: only: - master diff --git a/build.sbt b/build.sbt index 43b2ecdf4..b153b9aea 100644 --- a/build.sbt +++ b/build.sbt @@ -15,7 +15,7 @@ inThisBuild(List( ) )) -val coursierVersion0 = "2.0.0-RC6-15" +val coursierVersion0 = "2.0.0-RC6-16" lazy val `lm-coursier` = project .in(file("modules/lm-coursier")) diff --git a/modules/lm-coursier/src/main/scala/lmcoursier/CoursierConfiguration.scala b/modules/lm-coursier/src/main/scala/lmcoursier/CoursierConfiguration.scala index 44f0ab003..57ae835e5 100644 --- a/modules/lm-coursier/src/main/scala/lmcoursier/CoursierConfiguration.scala +++ b/modules/lm-coursier/src/main/scala/lmcoursier/CoursierConfiguration.scala @@ -52,6 +52,8 @@ import scala.concurrent.duration.Duration cachePolicies: Vector[CachePolicy] = CacheDefaults.cachePolicies.to[Vector].map(FromCoursier.cachePolicy), @since missingOk: Boolean = false, + @since + sbtClassifiers: Boolean = false ) { def withLog(log: Logger): CoursierConfiguration = diff --git a/modules/lm-coursier/src/main/scala/lmcoursier/CoursierDependencyResolution.scala b/modules/lm-coursier/src/main/scala/lmcoursier/CoursierDependencyResolution.scala index 6fb48c8fb..addf9b9ce 100644 --- a/modules/lm-coursier/src/main/scala/lmcoursier/CoursierDependencyResolution.scala +++ b/modules/lm-coursier/src/main/scala/lmcoursier/CoursierDependencyResolution.scala @@ -12,6 +12,8 @@ import lmcoursier.internal.{ArtifactsParams, ArtifactsRun, CoursierModuleDescrip import sbt.internal.librarymanagement.IvySbt import sbt.librarymanagement._ import sbt.util.Logger +import coursier.core.Dependency +import coursier.core.Publication class CoursierDependencyResolution(conf: CoursierConfiguration) extends DependencyResolutionInterface { @@ -150,7 +152,7 @@ class CoursierDependencyResolution(conf: CoursierConfiguration) extends Dependen parentProjectCache = Map.empty, interProjectDependencies = interProjectDependencies, internalRepositories = Seq(interProjectRepo, extraProjectsRepo), - sbtClassifiers = false, + sbtClassifiers = conf.sbtClassifiers, projectName = projectName, loggerOpt = loggerOpt, cache = cache0, @@ -172,10 +174,11 @@ class CoursierDependencyResolution(conf: CoursierConfiguration) extends Dependen includeSignatures = false, loggerOpt = loggerOpt, projectName = projectName, - sbtClassifiers = false, + sbtClassifiers = conf.sbtClassifiers, cache = cache0, parallel = conf.parallelDownloads, classpathOrder = conf.classpathOrder, + missingOk = conf.missingOk ) val sbtBootJarOverrides = SbtBootJars( @@ -191,12 +194,13 @@ class CoursierDependencyResolution(conf: CoursierConfiguration) extends Dependen def updateParams( resolutions: Map[Set[Configuration], Resolution], - artifacts: Map[Artifact, File] + artifacts: Seq[(Dependency, Publication, Artifact, Option[File])] ) = UpdateParams( thisModule = (ToCoursier.module(mod), ver), shadedConfigOpt = None, - artifacts = artifacts, + artifacts = artifacts.collect { case (d, p, a, Some(f)) => a -> f }.toMap, + fullArtifacts = Some(artifacts.map { case (d, p, a, f) => (d, p, a) -> f }.toMap), classifiers = classifiers, configs = configs, dependencies = dependencies, @@ -205,12 +209,13 @@ class CoursierDependencyResolution(conf: CoursierConfiguration) extends Dependen includeSignatures = false, sbtBootJarOverrides = sbtBootJarOverrides, classpathOrder = conf.classpathOrder, + missingOk = conf.missingOk ) val e = for { resolutions <- ResolutionRun.resolutions(resolutionParams, verbosityLevel, log) artifactsParams0 = artifactsParams(resolutions) - artifacts <- ArtifactsRun.artifacts(artifactsParams0, verbosityLevel, log) + artifacts <- ArtifactsRun.artifactsResult(artifactsParams0, verbosityLevel, log) } yield { val updateParams0 = updateParams(resolutions, artifacts) UpdateRun.update(updateParams0, verbosityLevel, log) diff --git a/modules/lm-coursier/src/main/scala/lmcoursier/FromSbt.scala b/modules/lm-coursier/src/main/scala/lmcoursier/FromSbt.scala index 088666e65..2e3c7bbeb 100644 --- a/modules/lm-coursier/src/main/scala/lmcoursier/FromSbt.scala +++ b/modules/lm-coursier/src/main/scala/lmcoursier/FromSbt.scala @@ -102,8 +102,8 @@ object FromSbt { } for { - (from, to) <- allMappings - pub <- publications + (from, to) <- allMappings.distinct + pub <- publications.distinct } yield { val dep0 = dep .withConfiguration(to) diff --git a/modules/lm-coursier/src/main/scala/lmcoursier/internal/ArtifactsParams.scala b/modules/lm-coursier/src/main/scala/lmcoursier/internal/ArtifactsParams.scala index 2f2873f7f..5873cbea9 100644 --- a/modules/lm-coursier/src/main/scala/lmcoursier/internal/ArtifactsParams.scala +++ b/modules/lm-coursier/src/main/scala/lmcoursier/internal/ArtifactsParams.scala @@ -15,4 +15,5 @@ final case class ArtifactsParams( cache: FileCache[Task], parallel: Int, classpathOrder: Boolean, + missingOk: Boolean ) diff --git a/modules/lm-coursier/src/main/scala/lmcoursier/internal/ArtifactsRun.scala b/modules/lm-coursier/src/main/scala/lmcoursier/internal/ArtifactsRun.scala index 86d746cef..f208fd2ec 100644 --- a/modules/lm-coursier/src/main/scala/lmcoursier/internal/ArtifactsRun.scala +++ b/modules/lm-coursier/src/main/scala/lmcoursier/internal/ArtifactsRun.scala @@ -7,6 +7,8 @@ import coursier.cache.loggers.{FallbackRefreshDisplay, ProgressBarRefreshDisplay import coursier.core.Type import coursier.util.Artifact import sbt.util.Logger +import coursier.core.Dependency +import coursier.core.Publication // private[coursier] object ArtifactsRun { @@ -16,6 +18,13 @@ object ArtifactsRun { verbosityLevel: Int, log: Logger ): Either[coursier.error.FetchError, Map[Artifact, File]] = + artifactsResult(params, verbosityLevel, log).map(_.collect { case (_, _, a, Some(f)) => (a, f) }.toMap) + + def artifactsResult( + params: ArtifactsParams, + verbosityLevel: Int, + log: Logger + ): Either[coursier.error.FetchError, Seq[(Dependency, Publication, Artifact, Option[File])]] = // let's update only one module at once, for a better output // Downloads are already parallel, no need to parallelize further anyway Lock.lock.synchronized { @@ -42,6 +51,15 @@ object ArtifactsRun { else Nil } + .addTransformArtifacts { artifacts => + if (params.missingOk) + artifacts.map { + case (dependency, publication, artifact) => + (dependency, publication, artifact.withOptional(true)) + } + else + artifacts + } .withCache( params .cache @@ -64,8 +82,8 @@ object ArtifactsRun { } ) ) - .either() - .map(_.toMap) + .eitherResult() + .map(_.fullDetailedArtifacts) // FIXME Misses extraArtifacts, that we don't use for now though } } diff --git a/modules/lm-coursier/src/main/scala/lmcoursier/internal/ResolutionParams.scala b/modules/lm-coursier/src/main/scala/lmcoursier/internal/ResolutionParams.scala index b262b3414..ced79bf3c 100644 --- a/modules/lm-coursier/src/main/scala/lmcoursier/internal/ResolutionParams.scala +++ b/modules/lm-coursier/src/main/scala/lmcoursier/internal/ResolutionParams.scala @@ -62,7 +62,7 @@ final case class ResolutionParams( cache = cleanCache ), cleanCache, - sbtClassifiers + missingOk ) } diff --git a/modules/lm-coursier/src/main/scala/lmcoursier/internal/SbtUpdateReport.scala b/modules/lm-coursier/src/main/scala/lmcoursier/internal/SbtUpdateReport.scala index 663a6cf5d..420b1fb34 100644 --- a/modules/lm-coursier/src/main/scala/lmcoursier/internal/SbtUpdateReport.scala +++ b/modules/lm-coursier/src/main/scala/lmcoursier/internal/SbtUpdateReport.scala @@ -137,19 +137,43 @@ private[internal] object SbtUpdateReport { interProjectDependencies: Seq[Project], classifiersOpt: Option[Seq[Classifier]], artifactFileOpt: (Module, String, Attributes, Artifact) => Option[File], + fullArtifactsOpt: Option[Map[(Dependency, Publication, Artifact), Option[File]]], log: Logger, keepPomArtifact: Boolean = false, includeSignatures: Boolean = false, classpathOrder: Boolean, + missingOk: Boolean ): Vector[ModuleReport] = { - val depArtifacts1 = res.dependencyArtifacts(classifiersOpt, classpathOrder) + + val deps = classifiersOpt match { + case Some(classifiers) => + res.dependencyArtifacts(Some(classifiers.toSeq), classpathOrder) + case None => + res.dependencyArtifacts(None, classpathOrder) + } + + val depArtifacts1 = fullArtifactsOpt match { + case Some(map) => + deps.map { + case (d, p, a) => + val d0 = d.withAttributes(d.attributes.withClassifier(p.classifier)) + val a0 = if (missingOk) a.withOptional(true) else a + val f = map.get((d0, p, a0)).flatten + (d, p, a0, f) // not d0 + } + case None => + deps.map { + case (d, p, a) => + (d, p, a, None) + } + } val depArtifacts0 = if (keepPomArtifact) depArtifacts1 else depArtifacts1.filter { - case (_, pub, _) => pub.attributes != Attributes(Type.pom, Classifier.empty) + case (_, pub, _, _) => pub.attributes != Attributes(Type.pom, Classifier.empty) } val depArtifacts = @@ -159,16 +183,16 @@ private[internal] object SbtUpdateReport { if (notFound.isEmpty) depArtifacts0.flatMap { - case (dep, pub, a) => + case (dep, pub, a, f) => val sigPub = pub // not too sure about those .withExt(Extension(pub.ext.value)) .withType(Type(pub.`type`.value)) - Seq((dep, pub, a)) ++ - a.extra.get("sig").toSeq.map((dep, sigPub, _)) + Seq((dep, pub, a, f)) ++ + a.extra.get("sig").toSeq.map((dep, sigPub, _, None)) } else { - for ((_, _, a) <- notFound) + for ((_, _, a, _) <- notFound) log.error(s"No signature found for ${a.url}") sys.error(s"${notFound.length} signature(s) not found") } @@ -178,7 +202,7 @@ private[internal] object SbtUpdateReport { val groupedDepArtifacts = { val m = depArtifacts.groupBy(_._1) val fromLib = depArtifacts.map(_._1).distinct.map { dep => - dep -> m.getOrElse(dep, Nil).map { case (_, pub, a) => (pub, a) } + dep -> m.getOrElse(dep, Nil).map { case (_, pub, a, f) => (pub, a, f) } } val fromInterProj = interProjectDependencies .filter(p => p.module != thisModule._1) @@ -249,11 +273,19 @@ private[internal] object SbtUpdateReport { Vector.empty } } + val filesOpt = artifacts.map { + case (pub, a, fileOpt) => + val fileOpt0 = fileOpt.orElse { + if (fullArtifactsOpt.isEmpty) artifactFileOpt(proj.module, proj.version, pub.attributes, a) + else None + } + (pub, a, fileOpt0) + } moduleReport(( dep, dependees, proj, - artifacts.map { case (pub, a) => (pub, a, artifactFileOpt(proj.module, proj.version, pub.attributes, a)) } + filesOpt )) } } @@ -266,10 +298,12 @@ private[internal] object SbtUpdateReport { configs: Map[Configuration, Set[Configuration]], classifiersOpt: Option[Seq[Classifier]], artifactFileOpt: (Module, String, Attributes, Artifact) => Option[File], + fullArtifactsOpt: Option[Map[(Dependency, Publication, Artifact), Option[File]]], log: Logger, keepPomArtifact: Boolean = false, includeSignatures: Boolean = false, classpathOrder: Boolean, + missingOk: Boolean ): UpdateReport = { val configReports = configs.map { @@ -288,10 +322,12 @@ private[internal] object SbtUpdateReport { interProjectDependencies, classifiersOpt, artifactFileOpt, + fullArtifactsOpt, log, keepPomArtifact = keepPomArtifact, includeSignatures = includeSignatures, classpathOrder = classpathOrder, + missingOk = missingOk ) val reports0 = subRes.rootDependencies match { diff --git a/modules/lm-coursier/src/main/scala/lmcoursier/internal/UpdateParams.scala b/modules/lm-coursier/src/main/scala/lmcoursier/internal/UpdateParams.scala index d7c20a6f8..5a5e641e9 100644 --- a/modules/lm-coursier/src/main/scala/lmcoursier/internal/UpdateParams.scala +++ b/modules/lm-coursier/src/main/scala/lmcoursier/internal/UpdateParams.scala @@ -10,6 +10,7 @@ final case class UpdateParams( thisModule: (Module, String), shadedConfigOpt: Option[(String, Configuration)], artifacts: Map[Artifact, File], + fullArtifacts: Option[Map[(Dependency, Publication, Artifact), Option[File]]], classifiers: Option[Seq[Classifier]], configs: Map[Configuration, Set[Configuration]], dependencies: Seq[(Configuration, Dependency)], @@ -18,6 +19,7 @@ final case class UpdateParams( includeSignatures: Boolean, sbtBootJarOverrides: Map[(Module, String), File], classpathOrder: Boolean, + missingOk: Boolean ) { def artifactFileOpt( @@ -37,7 +39,11 @@ final case class UpdateParams( else None - fromBootJars.orElse(artifacts.get(artifact)) + val artifact0 = + if (missingOk) artifact.withOptional(true) + else artifact + + fromBootJars.orElse(artifacts.get(artifact0)) } } diff --git a/modules/lm-coursier/src/main/scala/lmcoursier/internal/UpdateRun.scala b/modules/lm-coursier/src/main/scala/lmcoursier/internal/UpdateRun.scala index f4230c9b3..cdd548b8a 100644 --- a/modules/lm-coursier/src/main/scala/lmcoursier/internal/UpdateRun.scala +++ b/modules/lm-coursier/src/main/scala/lmcoursier/internal/UpdateRun.scala @@ -92,9 +92,11 @@ object UpdateRun { params.configs, params.classifiers, params.artifactFileOpt, + params.fullArtifacts, log, includeSignatures = params.includeSignatures, classpathOrder = params.classpathOrder, + missingOk = params.missingOk ) } diff --git a/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/ArtifactsTasks.scala b/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/ArtifactsTasks.scala index 364bfbaa7..bf2a41121 100644 --- a/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/ArtifactsTasks.scala +++ b/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/ArtifactsTasks.scala @@ -72,6 +72,7 @@ object ArtifactsTasks { .withFollowHttpToHttpsRedirections(true), parallel = parallelDownloads, classpathOrder = true, + missingOk = sbtClassifiers ) val resOrError = ArtifactsRun.artifacts( diff --git a/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/UpdateTasks.scala b/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/UpdateTasks.scala index 3e3577d4a..693cc9df3 100644 --- a/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/UpdateTasks.scala +++ b/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/UpdateTasks.scala @@ -130,6 +130,7 @@ object UpdateTasks { (p.module, p.version), shadedConfigOpt, artifactFilesOrErrors0, + None, classifiers, configs, dependencies, @@ -138,6 +139,7 @@ object UpdateTasks { includeSignatures, sbtBootJarOverrides, classpathOrder = true, + missingOk = sbtClassifiers ) val rep = UpdateRun.update(params, verbosityLevel, log) diff --git a/modules/sbt-coursier/src/sbt-test/shared-2/update-sbt-classifiers-2/build.sbt b/modules/sbt-coursier/src/sbt-test/shared-2/update-sbt-classifiers-2/build.sbt new file mode 100644 index 000000000..2dac5446b --- /dev/null +++ b/modules/sbt-coursier/src/sbt-test/shared-2/update-sbt-classifiers-2/build.sbt @@ -0,0 +1,50 @@ + +scalaVersion := appConfiguration.value.provider.scalaProvider.version + +lazy val updateSbtClassifiersCheck = TaskKey[Unit]("updateSbtClassifiersCheck") + +updateSbtClassifiersCheck := { + + val defaultModules = updateSbtClassifiers + .value + .configuration(Default) + .map(_.modules) + .getOrElse(Nil) + + val compileModules = updateSbtClassifiers + .value + .configuration(Compile) + .map(_.modules) + .getOrElse(Nil) + + def artifacts(org: String, name: String) = + (defaultModules ++ compileModules) + .map { m => + println(s"Found module $m") + m + } + .collect { + case moduleReport + if moduleReport.module.organization == org && + moduleReport.module.name == name => + moduleReport.artifacts + } + .toSeq + .flatten + + def ensureHasArtifact(orgName: (String, String)*) = + assert( + orgName.exists { + case (org, name) => + artifacts(org, name).exists(_._2.getName.endsWith("-sources.jar")) + }, + s"Any of $orgName not found" + ) + + ensureHasArtifact("org.scala-lang" -> "scala-library") + ensureHasArtifact("org.scala-lang.modules" -> s"scala-xml_${scalaBinaryVersion.value}") + ensureHasArtifact( + "io.get-coursier" -> s"lm-coursier_${scalaBinaryVersion.value}", + "io.get-coursier" -> s"lm-coursier-shaded_${scalaBinaryVersion.value}" + ) +} diff --git a/modules/sbt-coursier/src/sbt-test/shared-2/update-sbt-classifiers-2/project/plugins.sbt b/modules/sbt-coursier/src/sbt-test/shared-2/update-sbt-classifiers-2/project/plugins.sbt new file mode 100644 index 000000000..531a4d36f --- /dev/null +++ b/modules/sbt-coursier/src/sbt-test/shared-2/update-sbt-classifiers-2/project/plugins.sbt @@ -0,0 +1,15 @@ +addSbtPlugin { + + val name = sys.props.getOrElse( + "plugin.name", + sys.error("plugin.name Java property not set") + ) + val version = sys.props.getOrElse( + "plugin.version", + sys.error("plugin.version Java property not set") + ) + + "io.get-coursier" % name % version +} + +addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.8.0") diff --git a/modules/sbt-coursier/src/sbt-test/shared-2/update-sbt-classifiers-2/test b/modules/sbt-coursier/src/sbt-test/shared-2/update-sbt-classifiers-2/test new file mode 100644 index 000000000..f6351a4d9 --- /dev/null +++ b/modules/sbt-coursier/src/sbt-test/shared-2/update-sbt-classifiers-2/test @@ -0,0 +1 @@ +> updateSbtClassifiersCheck diff --git a/modules/sbt-lm-coursier/src/main/scala/coursier/sbtlmcoursier/LmCoursierPlugin.scala b/modules/sbt-lm-coursier/src/main/scala/coursier/sbtlmcoursier/LmCoursierPlugin.scala index b687e6627..cc8ce175e 100644 --- a/modules/sbt-lm-coursier/src/main/scala/coursier/sbtlmcoursier/LmCoursierPlugin.scala +++ b/modules/sbt-lm-coursier/src/main/scala/coursier/sbtlmcoursier/LmCoursierPlugin.scala @@ -11,6 +11,7 @@ import sbt.Keys.{appConfiguration, autoScalaLibrary, classpathTypes, dependencyO import sbt.librarymanagement.DependencyResolution import scala.language.reflectiveCalls +import sbt.TaskKey object LmCoursierPlugin extends AutoPlugin { @@ -38,6 +39,19 @@ object LmCoursierPlugin extends AutoPlugin { // so that it doesn't override us :| override def requires = SbtCoursierShared + private lazy val scalaCompilerBridgeScopeOpt: Option[TaskKey[Unit]] = + try { + // only added in sbt 1.3.x + val key = sbt.Keys + .asInstanceOf[{ def scalaCompilerBridgeScope: TaskKey[Unit] }] + .scalaCompilerBridgeScope + Some(key) + } + catch { + case _: NoSuchMethodError | _: NoSuchMethodException => + None + } + // putting this in projectSettings like sbt.plugins.IvyPlugin does :| override def projectSettings: Seq[Setting[_]] = Seq( @@ -59,7 +73,18 @@ object LmCoursierPlugin extends AutoPlugin { dependencyResolution := mkDependencyResolution.value, coursierConfiguration := mkCoursierConfiguration(sbtClassifiers = true).value ) - ) + ) ++ { + scalaCompilerBridgeScopeOpt match { + case None => Nil + case Some(scalaCompilerBridgeScopeKey) => + inTask(scalaCompilerBridgeScopeKey)( + Seq( + dependencyResolution := mkDependencyResolution.value, + coursierConfiguration := mkCoursierConfiguration().value + ) + ) + } + } private def mkCoursierConfiguration(withClassifiers: Boolean = false, sbtClassifiers: Boolean = false): Def.Initialize[Task[CoursierConfiguration]] = @@ -160,7 +185,9 @@ object LmCoursierPlugin extends AutoPlugin { .withIvyHome(ivyPaths.value.ivyHome) .withStrict(strict) .withForceVersions(userForceVersions.toVector) - .withMissingOk(updateConfig.missingOk) + // seems missingOk is false in the updateConfig of updateSbtClassifiers? + .withMissingOk(updateConfig.missingOk || sbtClassifiers) + .withSbtClassifiers(sbtClassifiers) } } private def mkDependencyResolution: Def.Initialize[Task[DependencyResolution]] = diff --git a/sbt b/sbt index 5acdead9a..6199f3986 100755 --- a/sbt +++ b/sbt @@ -6,11 +6,11 @@ set -o pipefail -declare -r sbt_release_version="1.2.8" -declare -r sbt_unreleased_version="1.3.0-RC1" +declare -r sbt_release_version="1.3.10" +declare -r sbt_unreleased_version="1.3.10" -declare -r latest_213="2.13.0" -declare -r latest_212="2.12.8" +declare -r latest_213="2.13.2" +declare -r latest_212="2.12.11" declare -r latest_211="2.11.12" declare -r latest_210="2.10.7" declare -r latest_29="2.9.3" @@ -18,21 +18,20 @@ declare -r latest_28="2.8.2" declare -r buildProps="project/build.properties" -declare -r sbt_launch_ivy_release_repo="http://repo.typesafe.com/typesafe/ivy-releases" +declare -r sbt_launch_ivy_release_repo="https://repo.typesafe.com/typesafe/ivy-releases" declare -r sbt_launch_ivy_snapshot_repo="https://repo.scala-sbt.org/scalasbt/ivy-snapshots" -declare -r sbt_launch_mvn_release_repo="http://repo.scala-sbt.org/scalasbt/maven-releases" -declare -r sbt_launch_mvn_snapshot_repo="http://repo.scala-sbt.org/scalasbt/maven-snapshots" +declare -r sbt_launch_mvn_release_repo="https://repo.scala-sbt.org/scalasbt/maven-releases" +declare -r sbt_launch_mvn_snapshot_repo="https://repo.scala-sbt.org/scalasbt/maven-snapshots" -declare -r default_jvm_opts_common="-Xms512m -Xss2m" -declare -r noshare_opts="-Dsbt.global.base=project/.sbtboot -Dsbt.boot.directory=project/.boot -Dsbt.ivy.home=project/.ivy" +declare -r default_jvm_opts_common="-Xms512m -Xss2m -XX:MaxInlineLevel=18" +declare -r noshare_opts="-Dsbt.global.base=project/.sbtboot -Dsbt.boot.directory=project/.boot -Dsbt.ivy.home=project/.ivy -Dsbt.coursier.home=project/.coursier" -declare -r default_coursier_launcher_version="1.2.17" +declare -r default_coursier_launcher_version="1.2.20" declare coursier_launcher_version="default" declare sbt_jar sbt_dir sbt_create sbt_version sbt_script sbt_new declare sbt_explicit_version declare verbose noshare batch trace_level -declare debugUs declare java_cmd="java" declare sbt_launch_dir="$HOME/.sbt/launchers" @@ -44,11 +43,14 @@ declare -a java_args coursier_args scalac_args sbt_commands residual_args # args to jvm/sbt via files or environment variables declare -a extra_jvm_opts extra_sbt_opts -echoerr () { echo >&2 "$@"; } -vlog () { [[ -n "$verbose" ]] && echoerr "$@"; } -die () { echo "Aborting: $*" ; exit 1; } +echoerr() { echo >&2 "$@"; } +vlog() { [[ -n "$verbose" ]] && echoerr "$@"; } +die() { + echo "Aborting: $*" + exit 1 +} -setTrapExit () { +setTrapExit() { # save stty and trap exit, to ensure echo is re-enabled if we are interrupted. SBT_STTY="$(stty -g 2>/dev/null)" export SBT_STTY @@ -67,9 +69,12 @@ setTrapExit () { # this seems to cover the bases on OSX, and someone will # have to tell me about the others. -get_script_path () { +get_script_path() { local path="$1" - [[ -L "$path" ]] || { echo "$path" ; return; } + [[ -L "$path" ]] || { + echo "$path" + return + } local -r target="$(readlink "$path")" if [[ "${target:0:1}" == "/" ]]; then @@ -84,7 +89,7 @@ declare -r script_path script_name="${script_path##*/}" declare -r script_name -init_default_option_file () { +init_default_option_file() { local overriding_var="${!1}" local default_file="$2" if [[ ! -r "$default_file" && "$overriding_var" =~ ^@(.*)$ ]]; then @@ -99,44 +104,44 @@ init_default_option_file () { sbt_opts_file="$(init_default_option_file SBT_OPTS .sbtopts)" jvm_opts_file="$(init_default_option_file JVM_OPTS .jvmopts)" -build_props_sbt () { - [[ -r "$buildProps" ]] && \ +build_props_sbt() { + [[ -r "$buildProps" ]] && grep '^sbt\.version' "$buildProps" | tr '=\r' ' ' | awk '{ print $2; }' } -set_sbt_version () { +set_sbt_version() { sbt_version="${sbt_explicit_version:-$(build_props_sbt)}" [[ -n "$sbt_version" ]] || sbt_version=$sbt_release_version export sbt_version } -url_base () { +url_base() { local version="$1" case "$version" in - 0.7.*) echo "http://simple-build-tool.googlecode.com" ;; - 0.10.* ) echo "$sbt_launch_ivy_release_repo" ;; + 0.7.*) echo "https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/simple-build-tool" ;; + 0.10.*) echo "$sbt_launch_ivy_release_repo" ;; 0.11.[12]) echo "$sbt_launch_ivy_release_repo" ;; 0.*-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9][0-9][0-9]) # ie "*-yyyymmdd-hhMMss" - echo "$sbt_launch_ivy_snapshot_repo" ;; - 0.*) echo "$sbt_launch_ivy_release_repo" ;; - *-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9][0-9][0-9]) # ie "*-yyyymmdd-hhMMss" - echo "$sbt_launch_mvn_snapshot_repo" ;; - *) echo "$sbt_launch_mvn_release_repo" ;; + echo "$sbt_launch_ivy_snapshot_repo" ;; + 0.*) echo "$sbt_launch_ivy_release_repo" ;; + *-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]T[0-9][0-9][0-9][0-9][0-9][0-9]) # ie "*-yyyymmddThhMMss" + echo "$sbt_launch_mvn_snapshot_repo" ;; + *) echo "$sbt_launch_mvn_release_repo" ;; esac } -make_url () { +make_url() { local version="$1" local base="${sbt_launch_repo:-$(url_base "$version")}" case "$version" in - 0.7.*) echo "$base/files/sbt-launch-0.7.7.jar" ;; - 0.10.* ) echo "$base/org.scala-tools.sbt/sbt-launch/$version/sbt-launch.jar" ;; + 0.7.*) echo "$base/sbt-launch-0.7.7.jar" ;; + 0.10.*) echo "$base/org.scala-tools.sbt/sbt-launch/$version/sbt-launch.jar" ;; 0.11.[12]) echo "$base/org.scala-tools.sbt/sbt-launch/$version/sbt-launch.jar" ;; - 0.*) echo "$base/org.scala-sbt/sbt-launch/$version/sbt-launch.jar" ;; - *) echo "$base/org/scala-sbt/sbt-launch/$version/sbt-launch.jar" ;; + 0.*) echo "$base/org.scala-sbt/sbt-launch/$version/sbt-launch.jar" ;; + *) echo "$base/org/scala-sbt/sbt-launch/$version/sbt-launch-${version}.jar" ;; esac } @@ -152,24 +157,37 @@ enable_coursier () { fi } -addJava () { vlog "[addJava] arg = '$1'" ; java_args+=("$1"); } -addCoursier () { vlog "[addCoursier] arg = '$1'"; coursier_args+=("$1"); } -addSbt () { vlog "[addSbt] arg = '$1'" ; sbt_commands+=("$1"); } -addScalac () { vlog "[addScalac] arg = '$1'" ; scalac_args+=("$1"); } -addResidual () { vlog "[residual] arg = '$1'" ; residual_args+=("$1"); } +addJava() { + vlog "[addJava] arg = '$1'" + java_args+=("$1") +} +addSbt() { + vlog "[addSbt] arg = '$1'" + sbt_commands+=("$1") +} +addScalac() { + vlog "[addScalac] arg = '$1'" + scalac_args+=("$1") +} +addResidual() { + vlog "[residual] arg = '$1'" + residual_args+=("$1") +} -addResolver () { addSbt "set resolvers += $1"; } -addDebugger () { addJava "-Xdebug" ; addJava "-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=$1"; } -setThisBuild () { +addResolver() { addSbt "set resolvers += $1"; } + +addDebugger() { addJava "-Xdebug" && addJava "-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=$1"; } + +setThisBuild() { vlog "[addBuild] args = '$*'" local key="$1" && shift addSbt "set $key in ThisBuild := $*" } -setScalaVersion () { +setScalaVersion() { [[ "$1" == *"-SNAPSHOT" ]] && addResolver 'Resolver.sonatypeRepo("snapshots")' addSbt "++ $1" } -setJavaHome () { +setJavaHome() { java_cmd="$1/bin/java" setThisBuild javaHome "_root_.scala.Some(file(\"$1\"))" export JAVA_HOME="$1" @@ -182,9 +200,9 @@ getJavaVersion() { # java -version on java8 says 1.8.x # but on 9 and 10 it's 9.x.y and 10.x.y. - if [[ "$str" =~ ^1\.([0-9]+)\..*$ ]]; then + if [[ "$str" =~ ^1\.([0-9]+)(\..*)?$ ]]; then echo "${BASH_REMATCH[1]}" - elif [[ "$str" =~ ^([0-9]+)\..*$ ]]; then + elif [[ "$str" =~ ^([0-9]+)(\..*)?$ ]]; then echo "${BASH_REMATCH[1]}" elif [[ -n "$str" ]]; then echoerr "Can't parse java version from: $str" @@ -194,8 +212,8 @@ getJavaVersion() { checkJava() { # Warn if there is a Java version mismatch between PATH and JAVA_HOME/JDK_HOME - [[ -n "$JAVA_HOME" && -e "$JAVA_HOME/bin/java" ]] && java="$JAVA_HOME/bin/java" - [[ -n "$JDK_HOME" && -e "$JDK_HOME/lib/tools.jar" ]] && java="$JDK_HOME/bin/java" + [[ -n "$JAVA_HOME" && -e "$JAVA_HOME/bin/java" ]] && java="$JAVA_HOME/bin/java" + [[ -n "$JDK_HOME" && -e "$JDK_HOME/lib/tools.jar" ]] && java="$JDK_HOME/bin/java" if [[ -n "$java" ]]; then pathJavaVersion=$(getJavaVersion java) @@ -209,31 +227,25 @@ checkJava() { fi } -java_version () { +java_version() { local -r version=$(getJavaVersion "$java_cmd") vlog "Detected Java version: $version" echo "$version" } # MaxPermSize critical on pre-8 JVMs but incurs noisy warning on 8+ -default_jvm_opts () { +default_jvm_opts() { local -r v="$(java_version)" - if [[ $v -ge 8 ]]; then + if [[ $v -ge 10 ]]; then + echo "$default_jvm_opts_common -XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler" + elif [[ $v -ge 8 ]]; then echo "$default_jvm_opts_common" else echo "-XX:MaxPermSize=384m $default_jvm_opts_common" fi } -build_props_scala () { - if [[ -r "$buildProps" ]]; then - versionLine="$(grep '^build.scala.versions' "$buildProps")" - versionString="${versionLine##build.scala.versions=}" - echo "${versionString%% .*}" - fi -} - -execRunner () { +execRunner() { # print the arguments one to a line, quoting any containing spaces vlog "# Executing command line:" && { for arg; do @@ -251,23 +263,23 @@ execRunner () { setTrapExit if [[ -n "$batch" ]]; then - "$@" < /dev/null + "$@" /dev/null 2>&1; then + if command -v curl >/dev/null 2>&1; then curl --fail --silent --location "$url" --output "$jar" - elif command -v wget > /dev/null 2>&1; then + elif command -v wget >/dev/null 2>&1; then wget -q -O "$jar" "$url" fi } && [[ -r "$jar" ]] } -acquire_sbt_jar () { +acquire_sbt_jar() { # if none of the options touched coursier_launcher_version, use the coursier # launcher with sbt >= 0.13.8 @@ -310,17 +322,68 @@ acquire_sbt_jar () { } || { if [[ -z "$coursier_launcher_version" ]]; then sbt_jar="$(jar_file "$sbt_version")" - download_url "$(make_url "$sbt_version")" "$sbt_jar" \ - "Downloading sbt launcher for $sbt_version:" + jar_url="$(make_url "$sbt_version")" + + download_url "${jar_url}" "${sbt_jar}" \ + "Downloading sbt launcher for ${sbt_version}:" + + case "${sbt_version}" in + 0.*) + vlog "SBT versions < 1.0 do not have published MD5 checksums, skipping check" + echo "" + ;; + *) verify_sbt_jar "${sbt_jar}" ;; + esac else sbt_jar="$(jar_file "coursier_$coursier_launcher_version")" download_url "$(make_coursier_url "$coursier_launcher_version")" "$sbt_jar" \ - "Downloading coursier sbt launcher $coursier_launcher_version:" + "Downloading coursier sbt launcher ${coursier_launcher_version}:" fi } } -usage () { +verify_sbt_jar() { + local jar="${1}" + local md5="${jar}.md5" + md5url="$(make_url "${sbt_version}").md5" + + echoerr "Downloading sbt launcher ${sbt_version} md5 hash:" + echoerr " From ${md5url}" + echoerr " To ${md5}" + + download_url "${md5url}" "${md5}" >/dev/null 2>&1 + + if command -v md5sum >/dev/null 2>&1; then + if echo "$(cat "${md5}") ${jar}" | md5sum -c -; then + rm -rf "${md5}" + return 0 + else + echoerr "Checksum does not match" + return 1 + fi + elif command -v md5 >/dev/null 2>&1; then + if [ "$(md5 -q "${jar}")" == "$(cat "${md5}")" ]; then + rm -rf "${md5}" + return 0 + else + echoerr "Checksum does not match" + return 1 + fi + elif command -v openssl >/dev/null 2>&1; then + if [ "$(openssl md5 -r "${jar}" | awk '{print $1}')" == "$(cat "${md5}")" ]; then + rm -rf "${md5}" + return 0 + else + echoerr "Checksum does not match" + return 1 + fi + else + echoerr "Could not find an MD5 command" + return 1 + fi +} + +usage() { set_sbt_version cat < use the specified version of sbt (default: $sbt_release_version) - -sbt-dev use the latest pre-release version of sbt: $sbt_unreleased_version - -sbt-jar use the specified jar as the sbt launcher - -sbt-launch-dir directory to hold sbt launchers (default: $sbt_launch_dir) - -sbt-launch-repo repo url for downloading sbt launcher jar (default: $(url_base "$sbt_version")) + -sbt-version use the specified version of sbt (default: $sbt_release_version) + -sbt-force-latest force the use of the latest release of sbt: $sbt_release_version + -sbt-dev use the latest pre-release version of sbt: $sbt_unreleased_version + -sbt-jar use the specified jar as the sbt launcher + -sbt-launch-dir directory to hold sbt launchers (default: $sbt_launch_dir) + -sbt-launch-repo repo url for downloading sbt launcher jar (default: $(url_base "$sbt_version")) # scala version (default: as chosen by sbt) - -28 use $latest_28 - -29 use $latest_29 - -210 use $latest_210 - -211 use $latest_211 - -212 use $latest_212 - -213 use $latest_213 - -scala-home use the scala build at the specified directory - -scala-version use the specified version of scala - -binary-version use the specified scala version when searching for dependencies + -28 use $latest_28 + -29 use $latest_29 + -210 use $latest_210 + -211 use $latest_211 + -212 use $latest_212 + -213 use $latest_213 + -scala-home use the scala build at the specified directory + -scala-version use the specified version of scala + -binary-version use the specified scala version when searching for dependencies # java version (default: java from PATH, currently $(java -version 2>&1 | grep version)) - -java-home alternate JAVA_HOME + -java-home alternate JAVA_HOME # passing options to the jvm - note it does NOT use JAVA_OPTS due to pollution # The default set is used if JVM_OPTS is unset and no -jvm-opts file is found - $(default_jvm_opts) - JVM_OPTS environment variable holding either the jvm args directly, or - the reference to a file containing jvm args if given path is prepended by '@' (e.g. '@/etc/jvmopts') - Note: "@"-file is overridden by local '.jvmopts' or '-jvm-opts' argument. - -jvm-opts file containing jvm args (if not given, .jvmopts in project root is used if present) - -Dkey=val pass -Dkey=val directly to the jvm - -J-X pass option -X directly to the jvm (-J is stripped) + $(default_jvm_opts) + JVM_OPTS environment variable holding either the jvm args directly, or + the reference to a file containing jvm args if given path is prepended by '@' (e.g. '@/etc/jvmopts') + Note: "@"-file is overridden by local '.jvmopts' or '-jvm-opts' argument. + -jvm-opts file containing jvm args (if not given, .jvmopts in project root is used if present) + -Dkey=val pass -Dkey=val directly to the jvm + -J-X pass option -X directly to the jvm (-J is stripped) # passing options to sbt, OR to this runner - SBT_OPTS environment variable holding either the sbt args directly, or - the reference to a file containing sbt args if given path is prepended by '@' (e.g. '@/etc/sbtopts') - Note: "@"-file is overridden by local '.sbtopts' or '-sbt-opts' argument. - -sbt-opts file containing sbt args (if not given, .sbtopts in project root is used if present) - -S-X add -X to sbt's scalacOptions (-S is stripped) + SBT_OPTS environment variable holding either the sbt args directly, or + the reference to a file containing sbt args if given path is prepended by '@' (e.g. '@/etc/sbtopts') + Note: "@"-file is overridden by local '.sbtopts' or '-sbt-opts' argument. + -sbt-opts file containing sbt args (if not given, .sbtopts in project root is used if present) + -S-X add -X to sbt's scalacOptions (-S is stripped) EOM + exit 0 } -process_args () { - require_arg () { +process_args() { + require_arg() { local type="$1" local opt="$2" local arg="$3" @@ -409,54 +467,60 @@ process_args () { } while [[ $# -gt 0 ]]; do case "$1" in - -h|-help) usage; exit 0 ;; - -v) verbose=true && shift ;; - -d) addSbt "--debug" && shift ;; - -w) addSbt "--warn" && shift ;; - -q) addSbt "--error" && shift ;; - -x) debugUs=true && shift ;; - -trace) require_arg integer "$1" "$2" && trace_level="$2" && shift 2 ;; - -ivy) require_arg path "$1" "$2" && addJava "-Dsbt.ivy.home=$2" && shift 2 ;; - -no-colors) addJava "-Dsbt.log.noformat=true" && shift ;; - -no-share) noshare=true && shift ;; - -sbt-boot) require_arg path "$1" "$2" && addJava "-Dsbt.boot.directory=$2" && shift 2 ;; - -sbt-dir) require_arg path "$1" "$2" && sbt_dir="$2" && shift 2 ;; - -debug-inc) addJava "-Dxsbt.inc.debug=true" && shift ;; - -offline) addSbt "set offline in Global := true" && shift ;; - -jvm-debug) require_arg port "$1" "$2" && addDebugger "$2" && shift 2 ;; - -batch) batch=true && shift ;; - -prompt) require_arg "expr" "$1" "$2" && setThisBuild shellPrompt "(s => { val e = Project.extract(s) ; $2 })" && shift 2 ;; - -script) require_arg file "$1" "$2" && sbt_script="$2" && addJava "-Dsbt.main.class=sbt.ScriptMain" && shift 2 ;; + -h | -help) usage ;; + -v) verbose=true && shift ;; + -d) addSbt "--debug" && shift ;; + -w) addSbt "--warn" && shift ;; + -q) addSbt "--error" && shift ;; + -x) shift ;; # currently unused + -trace) require_arg integer "$1" "$2" && trace_level="$2" && shift 2 ;; + -debug-inc) addJava "-Dxsbt.inc.debug=true" && shift ;; + + -no-colors) addJava "-Dsbt.log.noformat=true" && shift ;; + -sbt-create) sbt_create=true && shift ;; + -sbt-dir) require_arg path "$1" "$2" && sbt_dir="$2" && shift 2 ;; + -sbt-boot) require_arg path "$1" "$2" && addJava "-Dsbt.boot.directory=$2" && shift 2 ;; + -ivy) require_arg path "$1" "$2" && addJava "-Dsbt.ivy.home=$2" && shift 2 ;; + -no-share) noshare=true && shift ;; + -offline) addSbt "set offline in Global := true" && shift ;; + -jvm-debug) require_arg port "$1" "$2" && addDebugger "$2" && shift 2 ;; + -batch) batch=true && shift ;; + -prompt) require_arg "expr" "$1" "$2" && setThisBuild shellPrompt "(s => { val e = Project.extract(s) ; $2 })" && shift 2 ;; + -script) require_arg file "$1" "$2" && sbt_script="$2" && addJava "-Dsbt.main.class=sbt.ScriptMain" && shift 2 ;; - -sbt-create) sbt_create=true && shift ;; - -sbt-jar) require_arg path "$1" "$2" && sbt_jar="$2" && shift 2 ;; -sbt-version) require_arg version "$1" "$2" && sbt_explicit_version="$2" && shift 2 ;; - -sbt-force-latest) sbt_explicit_version="$sbt_release_version" && shift ;; - -sbt-dev) sbt_explicit_version="$sbt_unreleased_version" && shift ;; - -sbt-launch-dir) require_arg path "$1" "$2" && sbt_launch_dir="$2" && shift 2 ;; - -sbt-launch-repo) require_arg path "$1" "$2" && sbt_launch_repo="$2" && shift 2 ;; - -coursier) enable_coursier && shift ;; - -mainline) coursier_launcher_version="" && shift ;; - -coursier-version) require_arg version "$1" "$2" && coursier_launcher_version="$2" && shift 2 ;; - -scala-version) require_arg version "$1" "$2" && setScalaVersion "$2" && shift 2 ;; - -binary-version) require_arg version "$1" "$2" && setThisBuild scalaBinaryVersion "\"$2\"" && shift 2 ;; - -scala-home) require_arg path "$1" "$2" && setThisBuild scalaHome "_root_.scala.Some(file(\"$2\"))" && shift 2 ;; - -java-home) require_arg path "$1" "$2" && setJavaHome "$2" && shift 2 ;; - -sbt-opts) require_arg path "$1" "$2" && sbt_opts_file="$2" && shift 2 ;; - -jvm-opts) require_arg path "$1" "$2" && jvm_opts_file="$2" && shift 2 ;; + -sbt-force-latest) sbt_explicit_version="$sbt_release_version" && shift ;; + -sbt-dev) sbt_explicit_version="$sbt_unreleased_version" && shift ;; + -sbt-jar) require_arg path "$1" "$2" && sbt_jar="$2" && shift 2 ;; + -sbt-launch-dir) require_arg path "$1" "$2" && sbt_launch_dir="$2" && shift 2 ;; + -sbt-launch-repo) require_arg path "$1" "$2" && sbt_launch_repo="$2" && shift 2 ;; - -D*) addJava "$1" && shift ;; - -J*) addJava "${1:2}" && shift ;; - -S*) addScalac "${1:2}" && shift ;; - -C*) addCoursier "${1:2}" && shift ;; - -28) setScalaVersion "$latest_28" && shift ;; - -29) setScalaVersion "$latest_29" && shift ;; - -210) setScalaVersion "$latest_210" && shift ;; - -211) setScalaVersion "$latest_211" && shift ;; - -212) setScalaVersion "$latest_212" && shift ;; - -213) setScalaVersion "$latest_213" && shift ;; - new) sbt_new=true && : ${sbt_explicit_version:=$sbt_release_version} && addResidual "$1" && shift ;; - *) addResidual "$1" && shift ;; + -28) setScalaVersion "$latest_28" && shift ;; + -29) setScalaVersion "$latest_29" && shift ;; + -210) setScalaVersion "$latest_210" && shift ;; + -211) setScalaVersion "$latest_211" && shift ;; + -212) setScalaVersion "$latest_212" && shift ;; + -213) setScalaVersion "$latest_213" && shift ;; + + -coursier) enable_coursier && shift ;; + -mainline) coursier_launcher_version="" && shift ;; + -coursier-version) require_arg version "$1" "$2" && coursier_launcher_version="$2" && shift 2 ;; + + -scala-version) require_arg version "$1" "$2" && setScalaVersion "$2" && shift 2 ;; + -binary-version) require_arg version "$1" "$2" && setThisBuild scalaBinaryVersion "\"$2\"" && shift 2 ;; + -scala-home) require_arg path "$1" "$2" && setThisBuild scalaHome "_root_.scala.Some(file(\"$2\"))" && shift 2 ;; + -java-home) require_arg path "$1" "$2" && setJavaHome "$2" && shift 2 ;; + -sbt-opts) require_arg path "$1" "$2" && sbt_opts_file="$2" && shift 2 ;; + -jvm-opts) require_arg path "$1" "$2" && jvm_opts_file="$2" && shift 2 ;; + + -D*) addJava "$1" && shift ;; + -J*) addJava "${1:2}" && shift ;; + -S*) addScalac "${1:2}" && shift ;; + -C*) addCoursier "${1:2}" && shift ;; + + new) sbt_new=true && : ${sbt_explicit_version:=$sbt_release_version} && addResidual "$1" && shift ;; + + *) addResidual "$1" && shift ;; esac done } @@ -470,7 +534,7 @@ readConfigFile() { until $end; do read -r || end=true [[ $REPLY =~ ^# ]] || [[ -z $REPLY ]] || echo "$REPLY" - done < "$1" + done <"$1" } # if there are file/environment sbt_opts, process again so we @@ -480,7 +544,7 @@ if [[ -r "$sbt_opts_file" ]]; then while read -r opt; do extra_sbt_opts+=("$opt"); done < <(readConfigFile "$sbt_opts_file") elif [[ -n "$SBT_OPTS" && ! ("$SBT_OPTS" =~ ^@.*) ]]; then vlog "Using sbt options defined in variable \$SBT_OPTS" - IFS=" " read -r -a extra_sbt_opts <<< "$SBT_OPTS" + IFS=" " read -r -a extra_sbt_opts <<<"$SBT_OPTS" else vlog "No extra sbt options have been defined" fi @@ -499,8 +563,8 @@ checkJava # only exists in 0.12+ setTraceLevel() { case "$sbt_version" in - "0.7."* | "0.10."* | "0.11."* ) echoerr "Cannot set trace level in sbt version $sbt_version" ;; - *) setThisBuild traceLevel "$trace_level" ;; + "0.7."* | "0.10."* | "0.11."*) echoerr "Cannot set trace level in sbt version $sbt_version" ;; + *) setThisBuild traceLevel "$trace_level" ;; esac } @@ -511,12 +575,12 @@ setTraceLevel() { vlog "Detected sbt version $sbt_version" if [[ -n "$sbt_script" ]]; then - residual_args=( "$sbt_script" "${residual_args[@]}" ) + residual_args=("$sbt_script" "${residual_args[@]}") else # no args - alert them there's stuff in here - (( argumentCount > 0 )) || { + ((argumentCount > 0)) || { vlog "Starting $script_name: invoke with -help for other options" - residual_args=( shell ) + residual_args=(shell) } fi @@ -542,7 +606,7 @@ EOM # no jar? download it. [[ -r "$sbt_jar" ]] || acquire_sbt_jar || { # still no jar? uh-oh. - echo "Download failed. Obtain the jar manually and place it at $sbt_jar" + echo "Could not download and verify the launcher. Obtain the jar manually and place it at $sbt_jar" exit 1 } @@ -552,12 +616,12 @@ if [[ -n "$noshare" ]]; then done else case "$sbt_version" in - "0.7."* | "0.10."* | "0.11."* | "0.12."* ) + "0.7."* | "0.10."* | "0.11."* | "0.12."*) [[ -n "$sbt_dir" ]] || { sbt_dir="$HOME/.sbt/$sbt_version" vlog "Using $sbt_dir as sbt dir, -sbt-dir to override." } - ;; + ;; esac if [[ -n "$sbt_dir" ]]; then @@ -570,10 +634,10 @@ if [[ -r "$jvm_opts_file" ]]; then while read -r opt; do extra_jvm_opts+=("$opt"); done < <(readConfigFile "$jvm_opts_file") elif [[ -n "$JVM_OPTS" && ! ("$JVM_OPTS" =~ ^@.*) ]]; then vlog "Using jvm options defined in \$JVM_OPTS variable" - IFS=" " read -r -a extra_jvm_opts <<< "$JVM_OPTS" + IFS=" " read -r -a extra_jvm_opts <<<"$JVM_OPTS" else vlog "Using default jvm options" - IFS=" " read -r -a extra_jvm_opts <<< "$(default_jvm_opts)" + IFS=" " read -r -a extra_jvm_opts <<<"$( default_jvm_opts)" fi # traceLevel is 0.12+ @@ -586,46 +650,10 @@ fi addCoursier "--" } -main () { - execRunner "$java_cmd" \ - "${extra_jvm_opts[@]}" \ - "${java_args[@]}" \ - -jar "$sbt_jar" \ - "${coursier_args[@]}" \ - "${sbt_commands[@]}" \ - "${residual_args[@]}" -} - -# sbt inserts this string on certain lines when formatting is enabled: -# val OverwriteLine = "\r\u001BM\u001B[2K" -# ...in order not to spam the console with a million "Resolving" lines. -# Unfortunately that makes it that much harder to work with when -# we're not going to print those lines anyway. We strip that bit of -# line noise, but leave the other codes to preserve color. -mainFiltered () { - local -r excludeRegex=$(grep -E -v '^#|^$' ~/.sbtignore | paste -sd'|' -) - - echoLine () { - local -r line="$1" - local -r line1="${line//\r\x1BM\x1B\[2K//g}" # This strips the OverwriteLine code. - local -r line2="${line1//\x1B\[[0-9;]*[JKmsu]//g}" # This strips all codes - we test regexes against this. - - if [[ $line2 =~ $excludeRegex ]]; then - [[ -n $debugUs ]] && echo "[X] $line1" - else - [[ -n $debugUs ]] && echo " $line1" || echo "$line1" - fi - } - - echoLine "Starting sbt with output filtering enabled." - main | while read -r line; do echoLine "$line"; done -} - -# Only filter if there's a filter file and we don't see a known interactive command. -# Obviously this is super ad hoc but I don't know how to improve on it. Testing whether -# stdin is a terminal is useless because most of my use cases for this filtering are -# exactly when I'm at a terminal, running sbt non-interactively. -shouldFilter () { [[ -f ~/.sbtignore ]] && ! grep -E -q '\b(shell|console|consoleProject)\b' <<<"${residual_args[@]}"; } - -# run sbt -if shouldFilter; then mainFiltered; else main; fi +execRunner "$java_cmd" \ + "${extra_jvm_opts[@]}" \ + "${java_args[@]}" \ + -jar "$sbt_jar" \ + "${coursier_args[@]}" \ + "${sbt_commands[@]}" \ + "${residual_args[@]}"