diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1f5a99178..66334d7e2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,15 +23,15 @@ jobs: run: | git config --global core.autocrlf false git config --global core.eol lf - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: fetch-depth: 0 submodules: true - - uses: coursier/cache-action@v6.3 - - uses: coursier/setup-action@v1 + - uses: coursier/cache-action@v6.4 + - uses: coursier/setup-action@v1.3 with: jvm: 8 - apps: sbt-launcher + apps: sbt - run: scripts/ci.sh shell: bash env: @@ -43,15 +43,15 @@ jobs: if: github.event_name == 'push' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: fetch-depth: 0 submodules: true - - uses: coursier/cache-action@v6.3 - - uses: coursier/setup-action@v1 + - uses: coursier/cache-action@v6.4 + - uses: coursier/setup-action@v1.3 with: jvm: 8 - apps: sbt-launcher + apps: sbt - uses: olafurpg/setup-gpg@v3 - name: Release run: sbt ci-release diff --git a/.gitignore b/.gitignore index 1e1817089..43c4b45bb 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,8 @@ target/ # Metals / bloop .metals/ .bloop/ +metals.sbt +.vscode/ # Intellij .idea/ diff --git a/.scala-steward.conf b/.scala-steward.conf new file mode 100644 index 000000000..d9a4607f5 --- /dev/null +++ b/.scala-steward.conf @@ -0,0 +1,3 @@ +updates.pin = [ + { groupId = "org.slf4j", artifactId="slf4j-api", version = "1." } +] diff --git a/build.sbt b/build.sbt index 1353b2290..2af4122e5 100644 --- a/build.sbt +++ b/build.sbt @@ -62,6 +62,14 @@ lazy val scalafixGen = Def.taskDyn { } } +Global / excludeLintKeys += scriptedBufferLog +Global / excludeLintKeys += scriptedLaunchOpts + +def coursierVersion0 = "2.1.9" +def coursierDep = ("io.get-coursier" %% "coursier" % coursierVersion0) + .exclude("org.codehaus.plexus", "plexus-archiver") + .exclude("org.codehaus.plexus", "plexus-container-default") + def dataclassGen(data: Reference) = Def.taskDyn { val root = (ThisBuild / baseDirectory).value.toURI.toString val from = (data / Compile / sourceDirectory).value @@ -87,6 +95,8 @@ def lmIvy = Def.setting { } } +lazy val preTest = taskKey[Unit]("prep steps before tests") + lazy val definitions = project .in(file("modules/definitions")) .disablePlugins(MimaPlugin) @@ -94,7 +104,7 @@ lazy val definitions = project scalaVersion := scala3, crossScalaVersions := Seq(scala212, scala213, scala3), libraryDependencies ++= Seq( - ("io.get-coursier" %% "coursier" % coursierVersion0).cross(CrossVersion.for3Use2_13), + coursierDep, "net.hamnaberg" %% "dataclass-annotation" % dataclassScalafixV % Provided, lmIvy.value % Provided, ), @@ -102,6 +112,10 @@ lazy val definitions = project dontPublish, ) +// FIXME Ideally, we should depend on the same version of io.get-coursier.jniutils:windows-jni-utils that +// io.get-coursier::coursier depends on. +val jniUtilsVersion = "0.3.3" + lazy val `lm-coursier` = project .in(file("modules/lm-coursier")) .settings( @@ -110,7 +124,9 @@ lazy val `lm-coursier` = project Mima.settings, Mima.lmCoursierFilters, libraryDependencies ++= Seq( - ("io.get-coursier" %% "coursier" % coursierVersion0).cross(CrossVersion.for3Use2_13), + coursierDep, + "io.get-coursier" %% "coursier-sbt-maven-repository" % coursierVersion0, + "io.get-coursier.jniutils" % "windows-jni-utils-lmcoursier" % jniUtilsVersion, "net.hamnaberg" %% "dataclass-annotation" % dataclassScalafixV % Provided, // We depend on librarymanagement-ivy rather than just @@ -119,19 +135,16 @@ lazy val `lm-coursier` = project // IvySbt#Module (seems DependencyResolutionInterface.moduleDescriptor // is ignored). lmIvy.value, - ("org.scalatest" %% "scalatest" % "3.2.13" % Test).cross(CrossVersion.for3Use2_13), + ("org.scalatest" %% "scalatest" % "3.2.18" % Test).cross(CrossVersion.for3Use2_13), ), - Test / test := { - (publishLocal in customProtocolForTest212).value - (publishLocal in customProtocolForTest213).value - (publishLocal in customProtocolJavaForTest).value - (Test / test).value + Test / exportedProducts := { + (Test / preTest).value + (Test / exportedProducts).value }, - Test / testOnly := { - (publishLocal in customProtocolForTest212).value - (publishLocal in customProtocolForTest213).value - (publishLocal in customProtocolJavaForTest).value - (Test / testOnly).evaluated + Test / preTest := { + (customProtocolForTest212 / publishLocal).value + (customProtocolForTest213 / publishLocal).value + (customProtocolJavaForTest / publishLocal).value }, Compile / sourceGenerators += dataclassGen(definitions).taskValue, ) @@ -153,7 +166,11 @@ lazy val `lm-coursier-shaded` = project Mima.lmCoursierFilters, Mima.lmCoursierShadedFilters, Compile / sources := (`lm-coursier` / Compile / sources).value, - // shadedModules += "io.get-coursier" %% "coursier", + // shadedModules ++= Set( + // "io.get-coursier" %% "coursier", + // "io.get-coursier" %% "coursier-sbt-maven-repository", + // "io.get-coursier.jniutils" % "windows-jni-utils-lmcoursier" + // ), // validNamespaces += "lmcoursier", // validEntries ++= Set( // // FIXME Ideally, we should just strip those from the resulting JAR… @@ -162,13 +179,11 @@ lazy val `lm-coursier-shaded` = project // "licenses/extreme.indiana.edu.license.TXT", // "licenses/javolution.license.TXT", // "licenses/thoughtworks.TXT", - // "licenses/" + // "licenses/", // ), assemblyShadeRules := { val toShade = Seq( "coursier", - "shapeless", - "argonaut", "org.fusesource", "macrocompat", "io.github.alexarchambault.windowsansi", @@ -187,15 +202,21 @@ lazy val `lm-coursier-shaded` = project "scala.collection.compat", "scala.util.control.compat", "scala.xml", + "com.github.plokhotnyuk.jsoniter_scala", + "scala.cli", + "com.github.luben.zstd", + "javax.inject" // hope shading this is fine… It's probably pulled via plexus-archiver, that sbt shouldn't use anyway… ) for (ns <- toShade) yield ShadeRule.rename(ns + ".**" -> s"lmcoursier.internal.shaded.$ns.@1").inAll }, libraryDependencies ++= Seq( - ("io.get-coursier" %% "coursier" % coursierVersion0).cross(CrossVersion.for3Use2_13), + coursierDep, + "io.get-coursier" %% "coursier-sbt-maven-repository" % coursierVersion0, + "io.get-coursier.jniutils" % "windows-jni-utils-lmcoursier" % jniUtilsVersion, "net.hamnaberg" %% "dataclass-annotation" % dataclassScalafixV % Provided, lmIvy.value % Provided, - "org.scalatest" %% "scalatest" % "3.2.13" % Test, + "org.scalatest" %% "scalatest" % "3.2.18" % Test, ), conflictWarning := ConflictWarning.disable, dontPublish, @@ -208,7 +229,7 @@ lazy val `sbt-coursier-shared` = project .settings( plugin, generatePropertyFile, - libraryDependencies += "com.lihaoyi" %% "utest" % "0.8.0" % Test, + libraryDependencies += "com.lihaoyi" %% "utest" % "0.8.3" % Test, testFrameworks += new TestFramework("utest.runner.Framework") ) @@ -219,7 +240,7 @@ lazy val `sbt-coursier-shared-shaded` = project .settings( plugin, generatePropertyFile, - unmanagedSourceDirectories.in(Compile) := unmanagedSourceDirectories.in(Compile).in(`sbt-coursier-shared`).value + Compile / unmanagedSourceDirectories := (`sbt-coursier-shared` / Compile / unmanagedSourceDirectories).value ) lazy val `sbt-lm-coursier` = project @@ -229,14 +250,14 @@ lazy val `sbt-lm-coursier` = project .dependsOn(`sbt-coursier-shared-shaded`) .settings( plugin, - sbtTestDirectory := sbtTestDirectory.in(`sbt-coursier`).value, + sbtTestDirectory := (`sbt-coursier` / sbtTestDirectory).value, scriptedDependencies := { scriptedDependencies.value // TODO Get those automatically // (but shouldn't scripted itself handle that…?) - publishLocal.in(`lm-coursier-shaded`).value - publishLocal.in(`sbt-coursier-shared-shaded`).value + (`lm-coursier-shaded` / publishLocal).value + (`sbt-coursier-shared-shaded` / publishLocal).value } ) @@ -252,8 +273,8 @@ lazy val `sbt-coursier` = project // TODO Get dependency projects automatically // (but shouldn't scripted itself handle that…?) - publishLocal.in(`lm-coursier`).value - publishLocal.in(`sbt-coursier-shared`).value + (`lm-coursier` / publishLocal).value + (`sbt-coursier-shared` / publishLocal).value } ) @@ -293,6 +314,7 @@ lazy val `sbt-coursier-root` = project .in(file(".")) .disablePlugins(MimaPlugin) .aggregate( + definitions, `lm-coursier`, `lm-coursier-shaded`, `sbt-coursier`, @@ -302,6 +324,7 @@ lazy val `sbt-coursier-root` = project ) .settings( shared, - skip.in(publish) := true + (publish / skip) := true ) +Global / onChangedBuildSource := ReloadOnSourceChanges diff --git a/modules/definitions/src/main/scala/lmcoursier/CoursierConfiguration.scala b/modules/definitions/src/main/scala/lmcoursier/CoursierConfiguration.scala index d8784311d..357a11a72 100644 --- a/modules/definitions/src/main/scala/lmcoursier/CoursierConfiguration.scala +++ b/modules/definitions/src/main/scala/lmcoursier/CoursierConfiguration.scala @@ -1,16 +1,15 @@ package lmcoursier import java.io.File - -import dataclass.data -import dataclass.since +import dataclass.{data, since} import coursier.cache.CacheDefaults +import coursier.params.rule.{Rule, RuleResolution} import lmcoursier.credentials.Credentials import lmcoursier.definitions.{Authentication, CacheLogger, CachePolicy, FromCoursier, Module, ModuleMatchers, Project, Reconciliation, Strict} -import sbt.librarymanagement.{Resolver, UpdateConfiguration, ModuleID, CrossVersion, ModuleInfo, ModuleDescriptorConfiguration} +import sbt.librarymanagement.{CrossVersion, InclExclRule, ModuleDescriptorConfiguration, ModuleID, ModuleInfo, Resolver, UpdateConfiguration} import xsbti.Logger -import scala.concurrent.duration.Duration +import scala.concurrent.duration.{Duration, FiniteDuration} import java.net.URL import java.net.URLClassLoader @@ -60,4 +59,6 @@ import java.net.URLClassLoader providedInCompile: Boolean = false, // unused, kept for binary compatibility @since protocolHandlerDependencies: Seq[ModuleID] = Vector.empty, + retry: Option[(FiniteDuration, Int)] = None, + sameVersions: Seq[Set[InclExclRule]] = Nil, ) diff --git a/modules/definitions/src/main/scala/lmcoursier/credentials/DirectCredentials.scala b/modules/definitions/src/main/scala/lmcoursier/credentials/DirectCredentials.scala index 2904dcec8..f77e06606 100644 --- a/modules/definitions/src/main/scala/lmcoursier/credentials/DirectCredentials.scala +++ b/modules/definitions/src/main/scala/lmcoursier/credentials/DirectCredentials.scala @@ -10,10 +10,11 @@ import dataclass._ realm: Option[String] = None, @since("1.1") optional: Boolean = true, - @since("1.1") - matchHost: Boolean = false, @since("1.2") + matchHost: Boolean = false, + @since("1.3") httpsOnly: Boolean = true ) extends Credentials { + override def toString(): String = s"DirectCredentials(host=$host, username=$username)" } diff --git a/modules/definitions/src/main/scala/lmcoursier/definitions/Authentication.scala b/modules/definitions/src/main/scala/lmcoursier/definitions/Authentication.scala index c79d71366..5bb231e5d 100644 --- a/modules/definitions/src/main/scala/lmcoursier/definitions/Authentication.scala +++ b/modules/definitions/src/main/scala/lmcoursier/definitions/Authentication.scala @@ -7,9 +7,11 @@ import dataclass._ password: String, optional: Boolean = false, realmOpt: Option[String] = None, - @since + @since("1.0") headers: Seq[(String,String)] = Nil, + @since("1.1") httpsOnly: Boolean = true, + @since("1.2") passOnRedirect: Boolean = false ) { override def toString(): String = diff --git a/modules/lm-coursier/src/main/scala/lmcoursier/CoursierDependencyResolution.scala b/modules/lm-coursier/src/main/scala/lmcoursier/CoursierDependencyResolution.scala index a2d3bd93c..0c4dbac22 100644 --- a/modules/lm-coursier/src/main/scala/lmcoursier/CoursierDependencyResolution.scala +++ b/modules/lm-coursier/src/main/scala/lmcoursier/CoursierDependencyResolution.scala @@ -169,7 +169,7 @@ class CoursierDependencyResolution( val cache = conf.cache.getOrElse(CacheDefaults.location) val cachePolicies = conf.cachePolicies.map(ToCoursier.cachePolicy) val checksums = conf.checksums - val projectName = "" // used for logging only… + val projectName = module0.module.name val ivyProperties = ResolutionParams.defaultIvyProperties(conf.ivyHome) @@ -252,9 +252,11 @@ class CoursierDependencyResolution( .withForceVersion(conf.forceVersions.map { case (k, v) => (ToCoursier.module(k), v) }.toMap) .withTypelevel(typelevel) .withReconciliation(ToCoursier.reconciliation(conf.reconciliation)) - .withExclusions(excludeDependencies), + .withExclusions(excludeDependencies) + .withRules(ToCoursier.sameVersions(conf.sameVersions)), strictOpt = conf.strict.map(ToCoursier.strict), missingOk = conf.missingOk, + retry = conf.retry.getOrElse(ResolutionParams.defaultRetry), ) def artifactsParams(resolutions: Map[Configuration, Resolution]): ArtifactsParams = diff --git a/modules/lm-coursier/src/main/scala/lmcoursier/definitions/ToCoursier.scala b/modules/lm-coursier/src/main/scala/lmcoursier/definitions/ToCoursier.scala index 1d47c3d85..2edaf65d8 100644 --- a/modules/lm-coursier/src/main/scala/lmcoursier/definitions/ToCoursier.scala +++ b/modules/lm-coursier/src/main/scala/lmcoursier/definitions/ToCoursier.scala @@ -1,6 +1,7 @@ package lmcoursier.definitions import lmcoursier.credentials.{Credentials, DirectCredentials, FileCredentials} +import sbt.librarymanagement.InclExclRule // TODO Make private[lmcoursier] // private[coursier] @@ -31,11 +32,14 @@ object ToCoursier { .withHttpsOnly(authentication.httpsOnly) .withPassOnRedirect(authentication.passOnRedirect) - def module(module: Module): coursier.core.Module = + def module(mod: Module): coursier.core.Module = + module(mod.organization.value, mod.name.value, mod.attributes) + + def module(organization: String, name: String, attributes: Map[String, String] = Map.empty): coursier.core.Module = coursier.core.Module( - coursier.core.Organization(module.organization.value), - coursier.core.ModuleName(module.name.value), - module.attributes + coursier.core.Organization(organization), + coursier.core.ModuleName(name), + attributes ) def moduleMatchers(matcher: ModuleMatchers): coursier.util.ModuleMatchers = @@ -61,6 +65,13 @@ object ToCoursier { Vector[(coursier.util.ModuleMatchers, coursier.core.Reconciliation)] = rs map { case (m, r) => (moduleMatchers(m), reconciliation(r)) } + def sameVersions(sv: Seq[Set[InclExclRule]]): + Seq[(coursier.params.rule.SameVersion, coursier.params.rule.RuleResolution)] = + sv.map { libs => + val matchers = libs.map(rule => coursier.util.ModuleMatcher(module(rule.organization, rule.name))) + coursier.params.rule.SameVersion(matchers) -> coursier.params.rule.RuleResolution.TryResolve + } + def dependency(dependency: Dependency): coursier.core.Dependency = coursier.core.Dependency( module(dependency.module), 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 dd1c36837..4b6cbe32b 100644 --- a/modules/lm-coursier/src/main/scala/lmcoursier/internal/ResolutionParams.scala +++ b/modules/lm-coursier/src/main/scala/lmcoursier/internal/ResolutionParams.scala @@ -11,6 +11,7 @@ import lmcoursier.definitions.ToCoursier import coursier.util.Task import scala.collection.mutable +import scala.concurrent.duration.{DurationInt, FiniteDuration} // private[coursier] final case class ResolutionParams( @@ -30,6 +31,7 @@ final case class ResolutionParams( params: coursier.params.ResolutionParams, strictOpt: Option[Strict], missingOk: Boolean, + retry: (FiniteDuration, Int) ) { lazy val allConfigExtends: Map[Configuration, Set[Configuration]] = { @@ -111,4 +113,5 @@ object ResolutionParams { ) ++ sys.props } + val defaultRetry: (FiniteDuration, Int) = (1.seconds, 3) } diff --git a/modules/lm-coursier/src/main/scala/lmcoursier/internal/ResolutionRun.scala b/modules/lm-coursier/src/main/scala/lmcoursier/internal/ResolutionRun.scala index 9ca6942d8..91e30dbbf 100644 --- a/modules/lm-coursier/src/main/scala/lmcoursier/internal/ResolutionRun.scala +++ b/modules/lm-coursier/src/main/scala/lmcoursier/internal/ResolutionRun.scala @@ -1,13 +1,18 @@ package lmcoursier.internal import coursier.{Resolution, Resolve} +import coursier.cache.internal.ThreadUtil import coursier.cache.loggers.{FallbackRefreshDisplay, ProgressBarRefreshDisplay, RefreshLogger} import coursier.core._ +import coursier.error.ResolutionError +import coursier.error.ResolutionError.CantDownloadModule import coursier.ivy.IvyRepository -import coursier.maven.MavenRepository +import coursier.maven.MavenRepositoryLike import coursier.params.rule.RuleResolution +import coursier.util.Task import sbt.util.Logger +import scala.concurrent.duration.FiniteDuration import scala.collection.mutable // private[coursier] @@ -34,7 +39,7 @@ object ResolutionRun { params.mainRepositories ++ params.fallbackDependenciesRepositories - val rules = params.strictOpt.map(s => Seq((s, RuleResolution.Fail))).getOrElse(Nil) + val rules = params.params.rules ++ params.strictOpt.map(s => Seq((s, RuleResolution.Fail))).getOrElse(Nil) val printOptionalMessage = verbosityLevel >= 0 && verbosityLevel <= 1 @@ -63,7 +68,7 @@ object ResolutionRun { s"ivy:${r.pattern}" case _: InterProjectRepository => "inter-project" - case r: MavenRepository => + case r: MavenRepositoryLike => r.root case r => // should not happen @@ -79,47 +84,85 @@ object ResolutionRun { if (verbosityLevel >= 2) log.info(initialMessage) - Resolve() - // re-using various caches from a resolution of a configuration we extend - .withInitialResolution(startingResolutionOpt) - .withDependencies( - params.dependencies.collect { - case (config, dep) if configs(config) => - dep - } - ) - .withRepositories(repositories) - .withResolutionParams( - params - .params - .addForceVersion((if (isSandboxConfig) Nil else params.interProjectDependencies.map(_.moduleVersion)): _*) - .withForceScalaVersion(params.autoScalaLibOpt.nonEmpty) - .withScalaVersionOpt(params.autoScalaLibOpt.map(_._2)) - .withTypelevel(params.params.typelevel) - .withRules(rules) - ) - .withCache( - params - .cache - .withLogger( - params.loggerOpt.getOrElse { - RefreshLogger.create( - if (RefreshLogger.defaultFallbackMode) - new FallbackRefreshDisplay() - else - ProgressBarRefreshDisplay.create( - if (printOptionalMessage) log.info(initialMessage), - if (printOptionalMessage || verbosityLevel >= 2) - log.info(s"Resolved ${params.projectName} dependencies") - ) - ) - } - ) - ) - .either() match { - case Left(err) if params.missingOk => Right(err.resolution) - case others => others - } + val resolveTask: Resolve[Task] = { + Resolve() + // re-using various caches from a resolution of a configuration we extend + .withInitialResolution(startingResolutionOpt) + .withDependencies( + params.dependencies.collect { + case (config, dep) if configs(config) => + dep + } + ) + .withRepositories(repositories) + .withResolutionParams( + params + .params + .addForceVersion((if (isSandboxConfig) Nil else params.interProjectDependencies.map(_.moduleVersion)): _*) + .withForceScalaVersion(params.autoScalaLibOpt.nonEmpty) + .withScalaVersionOpt(params.autoScalaLibOpt.map(_._2)) + .withTypelevel(params.params.typelevel) + .withRules(rules) + ) + .withCache( + params + .cache + .withLogger( + params.loggerOpt.getOrElse { + RefreshLogger.create( + if (RefreshLogger.defaultFallbackMode) + new FallbackRefreshDisplay() + else + ProgressBarRefreshDisplay.create( + if (printOptionalMessage) log.info(initialMessage), + if (printOptionalMessage || verbosityLevel >= 2) + log.info(s"Resolved ${params.projectName} dependencies") + ) + ) + } + ) + ) + } + + val (period, maxAttempts) = params.retry + val finalResult: Either[ResolutionError, Resolution] = { + + def retry(attempt: Int, waitOnError: FiniteDuration): Task[Either[ResolutionError, Resolution]] = + resolveTask + .io + .attempt + .flatMap { + case Left(e: ResolutionError) => + val hasConnectionTimeouts = e.errors.exists { + case err: CantDownloadModule => err.perRepositoryErrors.exists(_.contains("Connection timed out")) + case _ => false + } + if (hasConnectionTimeouts) + if (attempt + 1 >= maxAttempts) { + log.error(s"Failed, maximum iterations ($maxAttempts) reached") + Task.point(Left(e)) + } + else { + log.warn(s"Attempt ${attempt + 1} failed: $e") + Task.completeAfter(retryScheduler, waitOnError).flatMap { _ => + retry(attempt + 1, waitOnError * 2) + } + } + else + Task.point(Left(e)) + case Left(ex) => + Task.fail(ex) + case Right(value) => + Task.point(Right(value)) + } + + retry(0, period).unsafeRun()(resolveTask.cache.ec) + } + + finalResult match { + case Left(err) if params.missingOk => Right(err.resolution) + case others => others + } } def resolutions( @@ -139,7 +182,7 @@ object ResolutionRun { SbtCoursierCache.default.resolutionOpt(params.resolutionKey).map(Right(_)).getOrElse { val resOrError = Lock.maybeSynchronized(needsLock = params.loggerOpt.nonEmpty || !RefreshLogger.defaultFallbackMode) { - var map = new mutable.HashMap[Configuration, Resolution] + val map = new mutable.HashMap[Configuration, Resolution] val either = params.orderedConfigs.foldLeft[Either[coursier.error.ResolutionError, Unit]](Right(())) { case (acc, (config, extends0)) => for { @@ -164,4 +207,5 @@ object ResolutionRun { } } + private lazy val retryScheduler = ThreadUtil.fixedScheduledThreadPool(1) } diff --git a/modules/lm-coursier/src/main/scala/lmcoursier/internal/Resolvers.scala b/modules/lm-coursier/src/main/scala/lmcoursier/internal/Resolvers.scala index a5b0a764a..51baf44ca 100644 --- a/modules/lm-coursier/src/main/scala/lmcoursier/internal/Resolvers.scala +++ b/modules/lm-coursier/src/main/scala/lmcoursier/internal/Resolvers.scala @@ -6,7 +6,7 @@ import java.nio.file.Paths import coursier.cache.CacheUrl import coursier.core.{Authentication, Repository} import coursier.ivy.IvyRepository -import coursier.maven.MavenRepository +import coursier.maven.SbtMavenRepository import org.apache.ivy.plugins.resolver.IBiblioResolver import sbt.librarymanagement.{Configuration => _, MavenRepository => _, _} import sbt.util.Logger @@ -17,8 +17,12 @@ object Resolvers { private def mavenCompatibleBaseOpt(patterns: Patterns): Option[String] = if (patterns.isMavenCompatible) { - val baseIvyPattern = patterns.ivyPatterns.head.takeWhile(c => c != '[' && c != '(') - val baseArtifactPattern = patterns.ivyPatterns.head.takeWhile(c => c != '[' && c != '(') + //input : /Users/user/custom/repo/[organisation]/[module](_[scalaVersion])(_[sbtVersion])/[revision]/[artifact]-[revision](-[classifier]).[ext] + //output : /Users/user/custom/repo/ + def basePattern(pattern: String): String = pattern.takeWhile(c => c != '[' && c != '(') + + val baseIvyPattern = basePattern(patterns.ivyPatterns.head) + val baseArtifactPattern = basePattern(patterns.artifactPatterns.head) if (baseIvyPattern == baseArtifactPattern) Some(baseIvyPattern) @@ -32,12 +36,12 @@ object Resolvers { log: Logger, authentication: Option[Authentication], classLoaders: Seq[ClassLoader] - ): Option[MavenRepository] = + ): Option[SbtMavenRepository] = try { CacheUrl.url(root, classLoaders) // ensure root is a URL whose protocol can be handled here val root0 = if (root.endsWith("/")) root else root + "/" Some( - MavenRepository( + SbtMavenRepository( root0, authentication = authentication ) 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 40c956b79..55bf9fc4a 100644 --- a/modules/lm-coursier/src/main/scala/lmcoursier/internal/SbtUpdateReport.scala +++ b/modules/lm-coursier/src/main/scala/lmcoursier/internal/SbtUpdateReport.scala @@ -47,7 +47,7 @@ private[internal] object SbtUpdateReport { .withExtraAttributes(dependency.module.attributes ++ extraProperties) .withExclusions( dependency - .exclusions + .minimizedExclusions .toVector .map { case (org, name) => diff --git a/modules/lm-coursier/src/main/scala/lmcoursier/syntax/package.scala b/modules/lm-coursier/src/main/scala/lmcoursier/syntax/package.scala index a6ed0df39..aef1d2a93 100644 --- a/modules/lm-coursier/src/main/scala/lmcoursier/syntax/package.scala +++ b/modules/lm-coursier/src/main/scala/lmcoursier/syntax/package.scala @@ -6,7 +6,7 @@ import lmcoursier.definitions._ import sbt.librarymanagement.{Resolver, UpdateConfiguration, ModuleID, CrossVersion, ModuleInfo, ModuleDescriptorConfiguration} import xsbti.Logger -import scala.concurrent.duration.Duration +import scala.concurrent.duration.{Duration, FiniteDuration} import java.io.File import java.net.URL import java.net.URLClassLoader @@ -74,6 +74,8 @@ package object syntax { sbtClassifiers = false, providedInCompile = false, protocolHandlerDependencies = Vector.empty, + retry = None, + sameVersions = Nil, ) } @@ -107,6 +109,9 @@ package object syntax { def withUpdateConfiguration(conf: UpdateConfiguration): CoursierConfiguration = value.withMissingOk(conf.missingOk) + + def withRetry(retry: (FiniteDuration, Int)): CoursierConfiguration = + value.withRetry(Some((retry._1, retry._2))) } implicit class PublicationOp(value: Publication) { diff --git a/modules/sbt-coursier-shared/src/main/scala/coursier/sbtcoursiershared/SbtCoursierShared.scala b/modules/sbt-coursier-shared/src/main/scala/coursier/sbtcoursiershared/SbtCoursierShared.scala index 11cb03ceb..5b0bd6118 100644 --- a/modules/sbt-coursier-shared/src/main/scala/coursier/sbtcoursiershared/SbtCoursierShared.scala +++ b/modules/sbt-coursier-shared/src/main/scala/coursier/sbtcoursiershared/SbtCoursierShared.scala @@ -12,6 +12,7 @@ import sbt.{AutoPlugin, Classpaths, Compile, Setting, TaskKey, Test, settingKey, import sbt.Keys._ import sbt.librarymanagement.DependencyBuilders.OrganizationArtifactName import sbt.librarymanagement.{ModuleID, Resolver, URLRepository} +import scala.concurrent.duration.FiniteDuration object SbtCoursierShared extends AutoPlugin { @@ -52,6 +53,8 @@ object SbtCoursierShared extends AutoPlugin { val coursierCache = settingKey[File]("") val sbtCoursierVersion = Properties.version + + val coursierRetry = taskKey[Option[(FiniteDuration, Int)]]("Retry for downloading dependencies") } import autoImport._ @@ -71,7 +74,8 @@ object SbtCoursierShared extends AutoPlugin { coursierReorderResolvers := true, coursierKeepPreloaded := false, coursierLogger := None, - coursierCache := CoursierDependencyResolution.defaultCacheLocation + coursierCache := CoursierDependencyResolution.defaultCacheLocation, + coursierRetry := None ) private val pluginIvySnapshotsBase = Resolver.SbtRepositoryRoot.stripSuffix("/") + "/ivy-snapshots" @@ -178,7 +182,8 @@ object SbtCoursierShared extends AutoPlugin { confs ++ extraSources.toSeq ++ extraDocs.toSeq }, mavenProfiles := Set.empty, - versionReconciliation := Seq.empty + versionReconciliation := Seq.empty, + coursierRetry := None ) ++ { if (pubSettings) IvyXmlGeneration.generateIvyXmlSettings diff --git a/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/Keys.scala b/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/Keys.scala index 6fe4a8d28..bf6ca9d9a 100644 --- a/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/Keys.scala +++ b/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/Keys.scala @@ -9,7 +9,7 @@ import coursier.util.Artifact import sbt.librarymanagement.{GetClassifiersModule, Resolver} import sbt.{InputKey, SettingKey, TaskKey} -import scala.concurrent.duration.Duration +import scala.concurrent.duration.{Duration, FiniteDuration} object Keys { val coursierParallelDownloads = SettingKey[Int]("coursier-parallel-downloads") diff --git a/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/ResolutionTasks.scala b/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/ResolutionTasks.scala index ae226cacd..eceb186ce 100644 --- a/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/ResolutionTasks.scala +++ b/modules/sbt-coursier/src/main/scala/coursier/sbtcoursier/ResolutionTasks.scala @@ -50,6 +50,8 @@ object ResolutionTasks { else Def.task(coursierRecursiveResolvers.value.distinct) + val retrySettings = Def.task(coursierRetry.value) + Def.task { val projectName = thisProjectRef.value.project @@ -169,6 +171,7 @@ object ResolutionTasks { .withExclusions(excludeDeps), strictOpt = strictOpt, missingOk = missingOk, + retry = retrySettings.value.getOrElse(ResolutionParams.defaultRetry) ), verbosityLevel, log diff --git a/modules/sbt-coursier/src/sbt-test/sbt-coursier/s3/build.sbt b/modules/sbt-coursier/src/sbt-test/sbt-coursier/s3/build.sbt index a62e6a917..4138b0846 100644 --- a/modules/sbt-coursier/src/sbt-test/sbt-coursier/s3/build.sbt +++ b/modules/sbt-coursier/src/sbt-test/sbt-coursier/s3/build.sbt @@ -44,7 +44,7 @@ check := { def containsRepo(repo: String): Boolean = { val accepted = Set(repo, repo.stripSuffix("/")) parsedCoursierResolvers.exists { - case m: coursier.maven.MavenRepository => accepted(m.root) + case m: coursier.maven.MavenRepositoryLike => accepted(m.root) case _ => false } } diff --git a/project/Settings.scala b/project/Settings.scala index b86fd8f42..2ef52b265 100644 --- a/project/Settings.scala +++ b/project/Settings.scala @@ -9,8 +9,8 @@ import com.jsuereth.sbtpgp._ object Settings { - def scala212 = "2.12.16" - def scala213 = "2.13.8" + def scala212 = "2.12.17" + def scala213 = "2.13.10" def scala3 = "3.3.1" def targetSbtVersion = "1.2.8" @@ -21,7 +21,7 @@ object Settings { } lazy val shared = Seq( - resolvers += Resolver.sonatypeRepo("releases"), + resolvers ++= Resolver.sonatypeOssRepos("releases"), crossScalaVersions := Seq(scala212), scalaVersion := scala3, scalacOptions ++= Seq( @@ -37,13 +37,20 @@ object Settings { scalacOptions ++= { if (isAtLeastScala213.value) Seq("-Ymacro-annotations") else Nil + }, + libraryDependencySchemes ++= { + val sv = scalaVersion.value + if (sv.startsWith("2.13.")) + Seq("org.scala-lang.modules" %% "scala-xml" % "always") + else + Nil } ) ++ { val prop = sys.props.getOrElse("publish.javadoc", "").toLowerCase(Locale.ROOT) if (prop == "0" || prop == "false") Seq( - sources in (Compile, doc) := Seq.empty, - publishArtifact in (Compile, packageDoc) := false + Compile / doc / sources := Seq.empty, + Compile / packageDoc / publishArtifact := false ) else Nil @@ -63,14 +70,14 @@ object Settings { ), scriptedBufferLog := false, sbtPlugin := true, - sbtVersion.in(pluginCrossBuild) := targetSbtVersion + pluginCrossBuild / sbtVersion := targetSbtVersion ) lazy val generatePropertyFile = - resourceGenerators.in(Compile) += Def.task { + Compile / resourceGenerators += Def.task { import sys.process._ - val dir = classDirectory.in(Compile).value / "coursier" + val dir = (Compile / classDirectory).value / "coursier" val ver = version.value val f = dir / "sbtcoursier.properties" diff --git a/project/plugins.sbt b/project/plugins.sbt index 764a88f16..6552bcc5a 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,9 +1,9 @@ semanticdbEnabled := false -addSbtPlugin("com.github.sbt" % "sbt-ci-release" % "1.5.10") -addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "1.1.0") -// addSbtPlugin("io.get-coursier" % "sbt-shading" % "2.1.0") +addSbtPlugin("com.github.sbt" % "sbt-ci-release" % "1.5.12") +addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "1.1.3") +// addSbtPlugin("io.get-coursier" % "sbt-shading" % "2.1.5") addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.0.0-RC1") -addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.10.1") +addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.12.1") libraryDependencies += "org.scala-sbt" %% "scripted-plugin" % sbtVersion.value diff --git a/sbt b/sbt deleted file mode 100755 index 9fc15a12a..000000000 --- a/sbt +++ /dev/null @@ -1,704 +0,0 @@ -#!/usr/bin/env bash -# -# A more capable sbt runner, coincidentally also called sbt. -# Author: Paul Phillips -# https://github.com/paulp/sbt-extras -# -# Generated from http://www.opensource.org/licenses/bsd-license.php -# Copyright (c) 2011, Paul Phillips. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# * Neither the name of the author nor the names of its contributors -# may be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -set -o pipefail - -declare -r sbt_release_version="1.4.0" -declare -r sbt_unreleased_version="1.4.0" - -declare -r latest_213="2.13.3" -declare -r latest_212="2.12.12" -declare -r latest_211="2.11.12" -declare -r latest_210="2.10.7" -declare -r latest_29="2.9.3" -declare -r latest_28="2.8.2" - -declare -r buildProps="project/build.properties" - -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="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 -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.22" -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 java_cmd="java" -declare sbt_launch_dir="$HOME/.sbt/launchers" -declare sbt_launch_repo - -# pull -J and -D options to give to java. -declare -a java_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 -} - -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 - - # restore stty settings (echo in particular) - onSbtRunnerExit() { - [ -t 0 ] || return - vlog "" - vlog "restoring stty: $SBT_STTY" - stty "$SBT_STTY" - } - - vlog "saving stty: $SBT_STTY" - trap onSbtRunnerExit EXIT -} - -# this seems to cover the bases on OSX, and someone will -# have to tell me about the others. -get_script_path() { - local path="$1" - [[ -L "$path" ]] || { - echo "$path" - return - } - - local -r target="$(readlink "$path")" - if [[ "${target:0:1}" == "/" ]]; then - echo "$target" - else - echo "${path%/*}/$target" - fi -} - -script_path="$(get_script_path "${BASH_SOURCE[0]}")" -declare -r script_path -script_name="${script_path##*/}" -declare -r script_name - -init_default_option_file() { - local overriding_var="${!1}" - local default_file="$2" - if [[ ! -r "$default_file" && "$overriding_var" =~ ^@(.*)$ ]]; then - local envvar_file="${BASH_REMATCH[1]}" - if [[ -r "$envvar_file" ]]; then - default_file="$envvar_file" - fi - fi - echo "$default_file" -} - -sbt_opts_file="$(init_default_option_file SBT_OPTS .sbtopts)" -sbtx_opts_file="$(init_default_option_file SBTX_OPTS .sbtxopts)" -jvm_opts_file="$(init_default_option_file JVM_OPTS .jvmopts)" - -build_props_sbt() { - [[ -r "$buildProps" ]] && - grep '^sbt\.version' "$buildProps" | tr '=\r' ' ' | awk '{ print $2; }' -} - -set_sbt_version() { - sbt_version="${sbt_explicit_version:-$(build_props_sbt)}" - [[ -n "$sbt_version" ]] || sbt_version=$sbt_release_version - export sbt_version -} - -url_base() { - local version="$1" - - case "$version" in - 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]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() { - local version="$1" - - local base="${sbt_launch_repo:-$(url_base "$version")}" - - case "$version" in - 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-${version}.jar" ;; - esac -} - -make_coursier_url () { - local version="$1" - - echo "https://github.com/coursier/sbt-launcher/releases/download/v$version/csbt" -} - -enable_coursier () { - if [[ -z "$coursier_launcher_version" ]]; then - coursier_launcher_version="$default_coursier_launcher_version" - fi -} - -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() { - vlog "[addBuild] args = '$*'" - local key="$1" && shift - addSbt "set $key in ThisBuild := $*" -} -setScalaVersion() { - [[ "$1" == *"-SNAPSHOT" ]] && addResolver 'Resolver.sonatypeRepo("snapshots")' - addSbt "++ $1" -} -setJavaHome() { - java_cmd="$1/bin/java" - setThisBuild javaHome "_root_.scala.Some(file(\"$1\"))" - export JAVA_HOME="$1" - export JDK_HOME="$1" - export PATH="$JAVA_HOME/bin:$PATH" -} - -getJavaVersion() { - local -r str=$("$1" -version 2>&1 | grep -E -e '(java|openjdk) version' | awk '{ print $3 }' | tr -d '"') - - # 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 - echo "${BASH_REMATCH[1]}" - elif [[ "$str" =~ ^([0-9]+)(\..*)?$ ]]; then - echo "${BASH_REMATCH[1]}" - elif [[ -n "$str" ]]; then - echoerr "Can't parse java version from: $str" - fi -} - -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" - - if [[ -n "$java" ]]; then - pathJavaVersion=$(getJavaVersion java) - homeJavaVersion=$(getJavaVersion "$java") - if [[ "$pathJavaVersion" != "$homeJavaVersion" ]]; then - echoerr "Warning: Java version mismatch between PATH and JAVA_HOME/JDK_HOME, sbt will use the one in PATH" - echoerr " Either: fix your PATH, remove JAVA_HOME/JDK_HOME or use -java-home" - echoerr " java version from PATH: $pathJavaVersion" - echoerr " java version from JAVA_HOME/JDK_HOME: $homeJavaVersion" - fi - fi -} - -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() { - local -r v="$(java_version)" - 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 -} - -execRunner() { - # print the arguments one to a line, quoting any containing spaces - vlog "# Executing command line:" && { - for arg; do - if [[ -n "$arg" ]]; then - if printf "%s\n" "$arg" | grep -q ' '; then - printf >&2 "\"%s\"\n" "$arg" - else - printf >&2 "%s\n" "$arg" - fi - fi - done - vlog "" - } - - setTrapExit - - if [[ -n "$batch" ]]; then - "$@" /dev/null 2>&1; then - curl --fail --silent --location "$url" --output "$jar" - elif command -v wget >/dev/null 2>&1; then - wget -q -O "$jar" "$url" - fi - } && [[ -r "$jar" ]] -} - -acquire_sbt_jar() { - - # if none of the options touched coursier_launcher_version, use the coursier - # launcher with sbt >= 0.13.8 - if [[ "$coursier_launcher_version" = "default" ]]; then - case "$sbt_version" in - 0.13.[89] | 0.13.1[0-9] | 1.* ) coursier_launcher_version="$default_coursier_launcher_version" ;; - * ) coursier_launcher_version="" ;; - esac - fi - - { - if [[ -z "$coursier_launcher_version" ]]; then - sbt_jar="$(jar_file "$sbt_version")" - else - sbt_jar="$(jar_file "coursier_$coursier_launcher_version")" - fi - - [[ -r "$sbt_jar" ]] - } || { - sbt_jar="$HOME/.ivy2/local/org.scala-sbt/sbt-launch/$sbt_version/jars/sbt-launch.jar" - [[ -z "$coursier_launcher_version" && -r "$sbt_jar" ]] - } || { - if [[ -z "$coursier_launcher_version" ]]; then - sbt_jar="$(jar_file "$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}:" - fi - } -} - -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 < display stack traces with a max of frames (default: -1, traces suppressed) - -debug-inc enable debugging log for the incremental compiler - -no-colors disable ANSI color codes - -sbt-create start sbt even if current directory contains no sbt project - -sbt-dir path to global settings/plugins directory (default: ~/.sbt/) - -sbt-boot path to shared boot directory (default: ~/.sbt/boot in 0.11+) - -ivy path to local Ivy repository (default: ~/.ivy2) - -no-share use all local caches; no sharing - -offline put sbt in offline mode - -jvm-debug Turn on JVM debugging, open at the given port. - -batch Disable interactive mode - -prompt Set the sbt prompt; in expr, 's' is the State and 'e' is Extracted - -script Run the specified file as a scala script - -coursier use a coursier-based launcher rather than an official sbt launcher (default) - -mainline use the mainline sbt launcher - - # sbt version (default: sbt.version from $buildProps if present, otherwise $sbt_release_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 - - # java version (default: java from PATH, currently $(java -version 2>&1 | grep version)) - -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) - - # 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) - - # passing options exclusively to this runner - SBTX_OPTS environment variable holding either the sbt-extras args directly, or - the reference to a file containing sbt-extras args if given path is prepended by '@' (e.g. '@/etc/sbtxopts') - Note: "@"-file is overridden by local '.sbtxopts' or '-sbtx-opts' argument. - -sbtx-opts file containing sbt-extras args (if not given, .sbtxopts in project root is used if present) -EOM - exit 0 -} - -process_args() { - require_arg() { - local type="$1" - local opt="$2" - local arg="$3" - - if [[ -z "$arg" ]] || [[ "${arg:0:1}" == "-" ]]; then - die "$opt requires <$type> argument" - fi - } - while [[ $# -gt 0 ]]; do - case "$1" in - -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-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-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 ;; - - -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 ;; - -sbtx-opts) require_arg path "$1" "$2" && sbtx_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 ;; - - new) sbt_new=true && : ${sbt_explicit_version:=$sbt_release_version} && addResidual "$1" && shift ;; - - *) addResidual "$1" && shift ;; - esac - done -} - -# process the direct command line arguments -process_args "$@" - -# skip #-styled comments and blank lines -readConfigFile() { - local end=false - until $end; do - read -r || end=true - [[ $REPLY =~ ^# ]] || [[ -z $REPLY ]] || echo "$REPLY" - done <"$1" -} - -# if there are file/environment sbt_opts, process again so we -# can supply args to this runner -if [[ -r "$sbt_opts_file" ]]; then - vlog "Using sbt options defined in file $sbt_opts_file" - 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" -else - vlog "No extra sbt options have been defined" -fi - -# if there are file/environment sbtx_opts, process again so we -# can supply args to this runner -if [[ -r "$sbtx_opts_file" ]]; then - vlog "Using sbt options defined in file $sbtx_opts_file" - while read -r opt; do extra_sbt_opts+=("$opt"); done < <(readConfigFile "$sbtx_opts_file") -elif [[ -n "$SBTX_OPTS" && ! ("$SBTX_OPTS" =~ ^@.*) ]]; then - vlog "Using sbt options defined in variable \$SBTX_OPTS" - IFS=" " read -r -a extra_sbt_opts <<<"$SBTX_OPTS" -else - vlog "No extra sbt options have been defined" -fi - -[[ -n "${extra_sbt_opts[*]}" ]] && process_args "${extra_sbt_opts[@]}" - -# reset "$@" to the residual args -set -- "${residual_args[@]}" -argumentCount=$# - -# set sbt version -set_sbt_version - -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" ;; - esac -} - -# set scalacOptions if we were given any -S opts -[[ ${#scalac_args[@]} -eq 0 ]] || addSbt "set scalacOptions in ThisBuild += \"${scalac_args[*]}\"" - -[[ -n "$sbt_explicit_version" && -z "$sbt_new" ]] && addJava "-Dsbt.version=$sbt_explicit_version" -vlog "Detected sbt version $sbt_version" - -if [[ -n "$sbt_script" ]]; then - residual_args=("$sbt_script" "${residual_args[@]}") -else - # no args - alert them there's stuff in here - ((argumentCount > 0)) || { - vlog "Starting $script_name: invoke with -help for other options" - residual_args=(shell) - } -fi - -# verify this is an sbt dir, -create was given or user attempts to run a scala script -[[ -r ./build.sbt || -d ./project || -n "$sbt_create" || -n "$sbt_script" || -n "$sbt_new" ]] || { - cat < 2.0.10-1) +# export COURSIER_JNI="force" + if [ "$(expr substr $(uname -s) 1 5 2>/dev/null)" == "Linux" ]; then - SBT="sbt -C--plugin-version=2.0.0-RC6-8" + SBT="sbt" elif [ "$(uname)" == "Darwin" ]; then - SBT="sbt -C--plugin-version=2.0.0-RC6-8" + SBT="sbt" else - SBT="sbt.bat -C--plugin-version=2.0.0-RC6-8" + SBT="sbt.bat" fi lmCoursier() { diff --git a/scripts/cs-setup.sh b/scripts/cs-setup.sh deleted file mode 100755 index 25f31b2aa..000000000 --- a/scripts/cs-setup.sh +++ /dev/null @@ -1,105 +0,0 @@ -#!/usr/bin/env bash - -# -# coursier launcher setup script -# See https://github.com/coursier/ci-scripts -# - - -set -e - -coursier_version="2.0.0-RC6-24" -for_graalvm="false" -dest="cs" - -# Adapted from https://github.com/paulp/sbt-extras/blob/ea47026bd55439760f4c5e9b27b002fa64a8b82f/sbt#L427-L435 and around -die() { - echo "Aborting: $*" - exit 1 -} -process_args() { - require_arg() { - local type="$1" - local opt="$2" - local arg="$3" - - if [[ -z "$arg" ]] || [[ "${arg:0:1}" == "-" ]]; then - die "$opt requires <$type> argument" - fi - } - parsing_args="true" - while [[ $# -gt 0 && "$parsing_args" == "true" ]]; do - case "$1" in - --version) require_arg version "$1" "$2" && coursier_version="$2" && shift 2 ;; - --dest) require_arg path "$1" "$2" && dest="$2" && shift 2 ;; - --graalvm) for_graalvm="true" && shift ;; - *) die "Unexpected argument: '$1'" ;; - esac - done -} - -process_args "$@" - - -do_chmod="1" -ext="" -setenv_bat="0" - -# https://stackoverflow.com/questions/3466166/how-to-check-if-running-in-cygwin-mac-or-linux/17072017#17072017 -if [ "$(expr substr $(uname -s) 1 5 2>/dev/null)" == "Linux" ]; then - cs_url="https://github.com/coursier/coursier/releases/download/v$coursier_version/cs-x86_64-pc-linux" - cache_base="$HOME/.cache/coursier/v1" -elif [ "$(uname)" == "Darwin" ]; then - cs_url="https://github.com/coursier/coursier/releases/download/v$coursier_version/cs-x86_64-apple-darwin" - cache_base="$HOME/Library/Caches/Coursier/v1" -else - # assuming Windows… - cs_url="https://github.com/coursier/coursier/releases/download/v$coursier_version/cs-x86_64-pc-win32.exe" - cache_base="$LOCALAPPDATA/Coursier/v1" # TODO Check that - ext=".exe" - do_chmod="0" - - if [ "$for_graalvm" = "true" ]; then - choco install -y windows-sdk-7.1 vcbuildtools kb2519277 - setenv_bat="1" - fi -fi - -cache_dest="$cache_base/$(echo "$cs_url" | sed 's@://@/@')" - -if [ -f "$cache_dest" ]; then - echo "Found $cache_dest in cache" -else - mkdir -p "$(dirname "$cache_dest")" - tmp_dest="$cache_dest.tmp-setup" - echo "Downloading $cs_url" - curl -Lo "$tmp_dest" "$cs_url" - mv "$tmp_dest" "$cache_dest" -fi - -if [ "$setenv_bat" = "1" ]; then - cp "$cache_dest" ".$dest$ext" - "./.$dest$ext" --help - if [ "$do_chmod" = "1" ]; then - chmod +x ".$dest$ext" - fi - cat > "$dest.bat" << EOF -@call "C:\\Program Files\\Microsoft SDKs\\Windows\\v7.1\\Bin\\SetEnv.Cmd" -%~dp0.$dest$ext %* -EOF - # that one is for bash - cat > "$dest" << EOF -#!/usr/bin/env bash -set -e -exec $(pwd)/$dest.bat "\$@" -EOF - chmod +x "$dest" || true -else - cp "$cache_dest" "$dest$ext" - if [ "$do_chmod" = "1" ]; then - chmod +x "$dest$ext" - fi -fi - -export PATH=".:$PATH" -"$dest" --help