diff --git a/build.sbt b/build.sbt index fac9a7008..cc2fa0300 100644 --- a/build.sbt +++ b/build.sbt @@ -267,7 +267,11 @@ lazy val lmCoursier = (project in file("coursier")) commonSettings, crossScalaVersions := Seq(scala212, scala211), name := "librarymanagement-coursier", - libraryDependencies ++= Seq(coursier, coursierCache, scalaTest, scalaCheck), + libraryDependencies ++= Seq(coursier, + coursierCache, + scalaTest % Test, + scalaCheck % Test + ), managedSourceDirectories in Compile += baseDirectory.value / "src" / "main" / "contraband-scala", sourceManaged in (Compile, generateContrabands) := baseDirectory.value / "src" / "main" / "contraband-scala", diff --git a/coursier/src/main/contraband-scala/sbt/librarymanagement/coursier/CoursierConfiguration.scala b/coursier/src/main/contraband-scala/sbt/librarymanagement/coursier/CoursierConfiguration.scala new file mode 100644 index 000000000..1864c4440 --- /dev/null +++ b/coursier/src/main/contraband-scala/sbt/librarymanagement/coursier/CoursierConfiguration.scala @@ -0,0 +1,57 @@ +/** + * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.librarymanagement.coursier +final class CoursierConfiguration private ( + val log: Option[xsbti.Logger], + val resolvers: Vector[sbt.librarymanagement.Resolver], + val otherResolvers: Vector[sbt.librarymanagement.Resolver], + val reorderResolvers: Boolean, + val parallelDownloads: Int, + val maxIterations: Int) extends Serializable { + + private def this() = this(None, sbt.librarymanagement.Resolver.defaults, Vector.empty, true, 6, 100) + + override def equals(o: Any): Boolean = o match { + case x: CoursierConfiguration => (this.log == x.log) && (this.resolvers == x.resolvers) && (this.otherResolvers == x.otherResolvers) && (this.reorderResolvers == x.reorderResolvers) && (this.parallelDownloads == x.parallelDownloads) && (this.maxIterations == x.maxIterations) + case _ => false + } + override def hashCode: Int = { + 37 * (37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbt.librarymanagement.coursier.CoursierConfiguration".##) + log.##) + resolvers.##) + otherResolvers.##) + reorderResolvers.##) + parallelDownloads.##) + maxIterations.##) + } + override def toString: String = { + "CoursierConfiguration(" + log + ", " + resolvers + ", " + otherResolvers + ", " + reorderResolvers + ", " + parallelDownloads + ", " + maxIterations + ")" + } + private[this] def copy(log: Option[xsbti.Logger] = log, resolvers: Vector[sbt.librarymanagement.Resolver] = resolvers, otherResolvers: Vector[sbt.librarymanagement.Resolver] = otherResolvers, reorderResolvers: Boolean = reorderResolvers, parallelDownloads: Int = parallelDownloads, maxIterations: Int = maxIterations): CoursierConfiguration = { + new CoursierConfiguration(log, resolvers, otherResolvers, reorderResolvers, parallelDownloads, maxIterations) + } + def withLog(log: Option[xsbti.Logger]): CoursierConfiguration = { + copy(log = log) + } + def withLog(log: xsbti.Logger): CoursierConfiguration = { + copy(log = Option(log)) + } + def withResolvers(resolvers: Vector[sbt.librarymanagement.Resolver]): CoursierConfiguration = { + copy(resolvers = resolvers) + } + def withOtherResolvers(otherResolvers: Vector[sbt.librarymanagement.Resolver]): CoursierConfiguration = { + copy(otherResolvers = otherResolvers) + } + def withReorderResolvers(reorderResolvers: Boolean): CoursierConfiguration = { + copy(reorderResolvers = reorderResolvers) + } + def withParallelDownloads(parallelDownloads: Int): CoursierConfiguration = { + copy(parallelDownloads = parallelDownloads) + } + def withMaxIterations(maxIterations: Int): CoursierConfiguration = { + copy(maxIterations = maxIterations) + } +} +object CoursierConfiguration { + + def apply(): CoursierConfiguration = new CoursierConfiguration() + def apply(log: Option[xsbti.Logger], resolvers: Vector[sbt.librarymanagement.Resolver], otherResolvers: Vector[sbt.librarymanagement.Resolver], reorderResolvers: Boolean, parallelDownloads: Int, maxIterations: Int): CoursierConfiguration = new CoursierConfiguration(log, resolvers, otherResolvers, reorderResolvers, parallelDownloads, maxIterations) + def apply(log: xsbti.Logger, resolvers: Vector[sbt.librarymanagement.Resolver], otherResolvers: Vector[sbt.librarymanagement.Resolver], reorderResolvers: Boolean, parallelDownloads: Int, maxIterations: Int): CoursierConfiguration = new CoursierConfiguration(Option(log), resolvers, otherResolvers, reorderResolvers, parallelDownloads, maxIterations) +} diff --git a/coursier/src/main/contraband-scala/sbt/librarymanagement/coursier/CoursierConfigurationFormats.scala b/coursier/src/main/contraband-scala/sbt/librarymanagement/coursier/CoursierConfigurationFormats.scala new file mode 100644 index 000000000..ff8713f87 --- /dev/null +++ b/coursier/src/main/contraband-scala/sbt/librarymanagement/coursier/CoursierConfigurationFormats.scala @@ -0,0 +1,37 @@ +/** + * This code is generated using [[http://www.scala-sbt.org/contraband/ sbt-contraband]]. + */ + +// DO NOT EDIT MANUALLY +package sbt.librarymanagement.coursier +import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError } +trait CoursierConfigurationFormats { self: sbt.internal.librarymanagement.formats.LoggerFormat with sbt.librarymanagement.ResolverFormats with sjsonnew.BasicJsonProtocol => +implicit lazy val CoursierConfigurationFormat: JsonFormat[sbt.librarymanagement.coursier.CoursierConfiguration] = new JsonFormat[sbt.librarymanagement.coursier.CoursierConfiguration] { + override def read[J](jsOpt: Option[J], unbuilder: Unbuilder[J]): sbt.librarymanagement.coursier.CoursierConfiguration = { + jsOpt match { + case Some(js) => + unbuilder.beginObject(js) + val log = unbuilder.readField[Option[xsbti.Logger]]("log") + val resolvers = unbuilder.readField[Vector[sbt.librarymanagement.Resolver]]("resolvers") + val otherResolvers = unbuilder.readField[Vector[sbt.librarymanagement.Resolver]]("otherResolvers") + val reorderResolvers = unbuilder.readField[Boolean]("reorderResolvers") + val parallelDownloads = unbuilder.readField[Int]("parallelDownloads") + val maxIterations = unbuilder.readField[Int]("maxIterations") + unbuilder.endObject() + sbt.librarymanagement.coursier.CoursierConfiguration(log, resolvers, otherResolvers, reorderResolvers, parallelDownloads, maxIterations) + case None => + deserializationError("Expected JsObject but found None") + } + } + override def write[J](obj: sbt.librarymanagement.coursier.CoursierConfiguration, builder: Builder[J]): Unit = { + builder.beginObject() + builder.addField("log", obj.log) + builder.addField("resolvers", obj.resolvers) + builder.addField("otherResolvers", obj.otherResolvers) + builder.addField("reorderResolvers", obj.reorderResolvers) + builder.addField("parallelDownloads", obj.parallelDownloads) + builder.addField("maxIterations", obj.maxIterations) + builder.endObject() + } +} +} diff --git a/coursier/src/main/contraband/lm-coursier.json b/coursier/src/main/contraband/lm-coursier.json new file mode 100644 index 000000000..927175607 --- /dev/null +++ b/coursier/src/main/contraband/lm-coursier.json @@ -0,0 +1,49 @@ +{ + "codecNamespace": "sbt.librarymanagement.coursier", + "types": [ + { + "name": "CoursierConfiguration", + "namespace": "sbt.librarymanagement.coursier", + "target": "Scala", + "type": "record", + "fields": [ + { + "name": "log", + "type": "xsbti.Logger?", + "default": "None", + "since": "0.0.1" + }, + { + "name": "resolvers", + "type": "sbt.librarymanagement.Resolver*", + "default": "sbt.librarymanagement.Resolver.defaults", + "since": "0.0.1" + }, + { + "name": "otherResolvers", + "type": "sbt.librarymanagement.Resolver*", + "default": "Vector.empty", + "since": "0.0.1" + }, + { + "name": "reorderResolvers", + "type": "Boolean", + "default": "true", + "since": "0.0.1" + }, + { + "name": "parallelDownloads", + "type": "Int", + "default": "6", + "since": "0.0.1" + }, + { + "name": "maxIterations", + "type": "Int", + "default": "100", + "since": "0.0.1" + } + ] + } + ] +} diff --git a/coursier/src/main/scala/sbt/librarymanagement/coursier/CoursierDependencyResolution.scala b/coursier/src/main/scala/sbt/librarymanagement/coursier/CoursierDependencyResolution.scala index c2434941c..4c60fce44 100644 --- a/coursier/src/main/scala/sbt/librarymanagement/coursier/CoursierDependencyResolution.scala +++ b/coursier/src/main/scala/sbt/librarymanagement/coursier/CoursierDependencyResolution.scala @@ -1,6 +1,9 @@ package sbt.librarymanagement.coursier import java.io.{ File, OutputStreamWriter } +import java.util.concurrent.Executors + +import scala.concurrent.ExecutionContext import coursier.{ Artifact, Resolution, _ } import coursier.util.{ Gather, Task } @@ -17,10 +20,22 @@ case class CoursierModuleDescriptor( case class CoursierModuleSettings() extends ModuleSettings -private[sbt] class CoursierDependencyResolution(resolvers: Vector[Resolver]) +private[sbt] class CoursierDependencyResolution(coursierConfiguration: CoursierConfiguration) extends DependencyResolutionInterface { - private[coursier] val reorderedResolvers = Resolvers.reorder(resolvers.toSeq) + // keep the pool alive while the class is loaded + private lazy val pool = + ExecutionContext.fromExecutor( + Executors.newFixedThreadPool(coursierConfiguration.parallelDownloads) + ) + + private[coursier] val reorderedResolvers = { + val _resolvers = + coursierConfiguration.resolvers ++ coursierConfiguration.otherResolvers + if (coursierConfiguration.reorderResolvers) { + Resolvers.reorder(_resolvers) + } else _resolvers + } /** * Builds a ModuleDescriptor that describes a subproject with dependencies. @@ -82,24 +97,34 @@ private[sbt] class CoursierDependencyResolution(resolvers: Vector[Resolver]) Cache.ivy2Local, Cache.ivy2Cache) - import scala.concurrent.ExecutionContext.Implicits.global + implicit val ec = pool - val fetch = Fetch.from(repositories, Cache.fetch[Task](logger = Some(createLogger()))) - val resolution = start.process.run(fetch).unsafeRun() - - if (resolution.errors.isEmpty) { - val localArtifacts: Map[Artifact, Either[FileError, File]] = Gather[Task] - .gather( - resolution.artifacts.map { a => - Cache.file[Task](a).run.map((a, _)) - } - ) + val coursierLogger = createLogger() + try { + val fetch = Fetch.from( + repositories, + Cache.fetch[Task](logger = Some(coursierLogger)) + ) + val resolution = start.process + .run(fetch, coursierConfiguration.maxIterations) .unsafeRun() - .toMap - toUpdateReport(resolution, localArtifacts, log) - } else { - toSbtError(log, uwconfig, resolution) + if (resolution.isDone && resolution.errors.isEmpty && resolution.conflicts.isEmpty) { + val localArtifacts: Map[Artifact, Either[FileError, File]] = Gather[Task] + .gather( + resolution.artifacts.map { a => + Cache.file[Task](a, logger = Some(coursierLogger)).run.map((a, _)) + } + ) + .unsafeRun() + .toMap + + toUpdateReport(resolution, localArtifacts, log) + } else { + toSbtError(log, uwconfig, resolution) + } + } finally { + coursierLogger.stop() } } @@ -254,6 +279,6 @@ private[sbt] class CoursierDependencyResolution(resolvers: Vector[Resolver]) } object CoursierDependencyResolution { - def apply(resolvers: Vector[Resolver]) = - DependencyResolution(new CoursierDependencyResolution(resolvers)) + def apply(configuration: CoursierConfiguration) = + DependencyResolution(new CoursierDependencyResolution(configuration)) } diff --git a/coursier/src/test/scala/sbt/librarymanagement/coursier/BaseCoursierSpecification.scala b/coursier/src/test/scala/sbt/librarymanagement/coursier/BaseCoursierSpecification.scala index 4fe2e3d0e..20545bcf3 100644 --- a/coursier/src/test/scala/sbt/librarymanagement/coursier/BaseCoursierSpecification.scala +++ b/coursier/src/test/scala/sbt/librarymanagement/coursier/BaseCoursierSpecification.scala @@ -34,4 +34,7 @@ trait BaseCoursierSpecification extends UnitSpec { def resolvers: Vector[Resolver] + def configuration(res: Vector[Resolver] = resolvers) = + CoursierConfiguration().withResolvers(res) + } diff --git a/coursier/src/test/scala/sbt/librarymanagement/coursier/ResolutionSpec.scala b/coursier/src/test/scala/sbt/librarymanagement/coursier/ResolutionSpec.scala index 55f636ce2..80fa40f24 100644 --- a/coursier/src/test/scala/sbt/librarymanagement/coursier/ResolutionSpec.scala +++ b/coursier/src/test/scala/sbt/librarymanagement/coursier/ResolutionSpec.scala @@ -10,14 +10,14 @@ import sbt.librarymanagement.syntax._ import sbt.librarymanagement.{ Resolver, UnresolvedWarningConfiguration, UpdateConfiguration } class ResolutionSpec extends BaseCoursierSpecification { - override val resolvers = Vector( + override def resolvers = Vector( DefaultMavenRepository, JavaNet2Repository, JCenterRepository, Resolver.sbtPluginRepo("releases") ) - val lmEngine = new CoursierDependencyResolution(resolvers) + val lmEngine = new CoursierDependencyResolution(configuration()) private final val stubModule = "com.example" % "foo" % "0.1.0" % "compile" @@ -78,7 +78,9 @@ class ResolutionSpec extends BaseCoursierSpecification { val dependencies = Vector(("org.scala-sbt" % "compiler-interface" % "1.0.4" % "component").sources()) val lmEngine = - CoursierDependencyResolution.apply(Resolver.combineDefaultResolvers(Vector.empty)) + CoursierDependencyResolution.apply( + configuration(Resolver.combineDefaultResolvers(Vector.empty)) + ) val coursierModule = module(stubModule, dependencies, Some("2.12.4")) val resolution = lmEngine.update(coursierModule, UpdateConfiguration(), UnresolvedWarningConfiguration(), log) @@ -128,7 +130,7 @@ class ResolutionSpec extends BaseCoursierSpecification { Resolver.sbtPluginRepo("releases"), DefaultMavenRepository ) - val engine = new CoursierDependencyResolution(resolvers) + val engine = new CoursierDependencyResolution(configuration(resolvers)) engine.reorderedResolvers.head.name should be("public") engine.reorderedResolvers.last.name should be("sbt-plugin-releases") engine.reorderedResolvers should have size 3 @@ -136,7 +138,7 @@ class ResolutionSpec extends BaseCoursierSpecification { it should "reorder default resolvers" in { val resolvers = Resolver.combineDefaultResolvers(Vector.empty) - val engine = new CoursierDependencyResolution(resolvers) + val engine = new CoursierDependencyResolution(configuration(resolvers)) engine.reorderedResolvers should not be 'empty engine.reorderedResolvers.head.name should be("public") } diff --git a/scripted-test/src/sbt-test/lmScriptedTest/sbt-plugins/build.sbt b/scripted-test/src/sbt-test/lmScriptedTest/sbt-plugins/build.sbt index da5f3491e..0a0172b37 100644 --- a/scripted-test/src/sbt-test/lmScriptedTest/sbt-plugins/build.sbt +++ b/scripted-test/src/sbt-test/lmScriptedTest/sbt-plugins/build.sbt @@ -18,10 +18,10 @@ """set dependencyResolution := sbt.librarymanagement.ivy.IvyDependencyResolution(ivyConfiguration.value)""" ) case Some("coursier") => - writePluginsSbt("""dependencyResolution := sbt.librarymanagement.coursier.CoursierDependencyResolution(Resolver.combineDefaultResolvers(resolvers.value.toVector))""") + writePluginsSbt("""dependencyResolution := sbt.librarymanagement.coursier.CoursierDependencyResolution(sbt.librarymanagement.coursier.CoursierConfiguration())""") addCommandAlias( "setDependencyResolution", - """set dependencyResolution := sbt.librarymanagement.coursier.CoursierDependencyResolution(Resolver.combineDefaultResolvers(resolvers.value.toVector))""" + """set dependencyResolution := sbt.librarymanagement.coursier.CoursierDependencyResolution(sbt.librarymanagement.coursier.CoursierConfiguration())""" ) case _ => sys.error("""|The system property 'dependency.resolution' is not defined. |Specify this property using the scriptedLaunchOpts -D.""".stripMargin) diff --git a/scripted-test/src/sbt-test/lmScriptedTest/simple/build.sbt b/scripted-test/src/sbt-test/lmScriptedTest/simple/build.sbt index 88debbcd1..7b0e47a38 100644 --- a/scripted-test/src/sbt-test/lmScriptedTest/simple/build.sbt +++ b/scripted-test/src/sbt-test/lmScriptedTest/simple/build.sbt @@ -8,7 +8,7 @@ sys.props.get("dependency.resolution") match { case Some("coursier") => addCommandAlias( "setDependencyResolution", - """set dependencyResolution := sbt.librarymanagement.coursier.CoursierDependencyResolution(Resolver.combineDefaultResolvers(resolvers.value.toVector))""" + """set dependencyResolution := sbt.librarymanagement.coursier.CoursierDependencyResolution(sbt.librarymanagement.coursier.CoursierConfiguration())""" ) case _ => sys.error("""|The system property 'dependency.resolution' is not defined. |Specify this property using the scriptedLaunchOpts -D.""".stripMargin) diff --git a/scripted-test/src/sbt-test/lmScriptedTest/with-trasnsitive/build.sbt b/scripted-test/src/sbt-test/lmScriptedTest/with-trasnsitive/build.sbt index 840a59a00..460935447 100644 --- a/scripted-test/src/sbt-test/lmScriptedTest/with-trasnsitive/build.sbt +++ b/scripted-test/src/sbt-test/lmScriptedTest/with-trasnsitive/build.sbt @@ -8,7 +8,7 @@ sys.props.get("dependency.resolution") match { case Some("coursier") => addCommandAlias( "setDependencyResolution", - """set dependencyResolution := sbt.librarymanagement.coursier.CoursierDependencyResolution(Resolver.combineDefaultResolvers(resolvers.value.toVector))""" + """set dependencyResolution := sbt.librarymanagement.coursier.CoursierDependencyResolution(sbt.librarymanagement.coursier.CoursierConfiguration())""" ) case _ => sys.error("""|The system property 'dependency.resolution' is not defined. |Specify this property using the scriptedLaunchOpts -D.""".stripMargin)