Merge pull request #212 from alexarchambault/topic/sbt-scripted-tests

Add support for fallback artifact (from) and excludeDependencies in SBT plugin
This commit is contained in:
Alexandre Archambault 2016-04-01 12:40:24 +02:00
commit e1cf438feb
19 changed files with 295 additions and 14 deletions

View File

@ -400,9 +400,23 @@ lazy val plugin = project
sbtPlugin := {
scalaVersion.value.startsWith("2.10.")
},
// added so that 2.10 artifacts of the other modules can be found by
// the too-naive-for-now inter-project resolver of the coursier SBT plugin
resolvers += Resolver.sonatypeRepo("snapshots")
resolvers ++= Seq(
// added so that 2.10 artifacts of the other modules can be found by
// the too-naive-for-now inter-project resolver of the coursier SBT plugin
Resolver.sonatypeRepo("snapshots"),
// added for sbt-scripted to be fine even with ++2.11.x
Resolver.typesafeIvyRepo("releases")
)
)
.settings(ScriptedPlugin.scriptedSettings)
.settings(
scriptedLaunchOpts ++= Seq(
"-Xmx1024M",
"-XX:MaxPermSize=256M",
"-Dplugin.version=" + version.value,
"-Dsbttest.base=" + (sourceDirectory.value / "sbt-test").getAbsolutePath
),
scriptedBufferLog := false
)
lazy val `coursier` = project.in(file("."))

View File

@ -20,6 +20,7 @@ object CoursierPlugin extends AutoPlugin {
val coursierVerbosity = Keys.coursierVerbosity
val coursierResolvers = Keys.coursierResolvers
val coursierSbtResolvers = Keys.coursierSbtResolvers
val coursierFallbackDependencies = Keys.coursierFallbackDependencies
val coursierCache = Keys.coursierCache
val coursierProject = Keys.coursierProject
val coursierProjects = Keys.coursierProjects
@ -39,6 +40,7 @@ object CoursierPlugin extends AutoPlugin {
coursierVerbosity := Settings.defaultVerbosityLevel,
coursierResolvers <<= Tasks.coursierResolversTask,
coursierSbtResolvers <<= externalResolvers in updateSbtClassifiers,
coursierFallbackDependencies <<= Tasks.coursierFallbackDependenciesTask,
coursierCache := Cache.default,
update <<= Tasks.updateTask(withClassifiers = false),
updateClassifiers <<= Tasks.updateTask(withClassifiers = true),

View File

@ -0,0 +1,55 @@
package coursier
import java.net.URL
import scalaz.{ EitherT, Monad }
case class FallbackDependenciesRepository(
fallbacks: Map[(Module, String), (URL, Boolean)]
) extends Repository {
private val source = new Artifact.Source {
def artifacts(
dependency: Dependency,
project: Project,
overrideClassifiers: Option[Seq[String]]
) =
fallbacks.get(dependency.moduleVersion) match {
case None => Nil
case Some((url, changing)) =>
Seq(
Artifact(url.toString, Map.empty, Map.empty, Attributes("jar", ""), changing)
)
}
}
def find[F[_]](
module: Module,
version: String,
fetch: Fetch.Content[F]
)(implicit
F: Monad[F]
): EitherT[F, String, (Artifact.Source, Project)] =
fallbacks.get((module, version)) match {
case None =>
EitherT.left(F.point("No fallback URL found"))
case Some((url, _)) =>
val proj = Project(
module,
version,
Nil,
Map.empty,
None,
Nil,
Nil,
Nil,
None,
None,
Nil,
Info.empty
)
EitherT.right(F.point((source, proj)))
}
}

View File

@ -2,7 +2,7 @@ package coursier
import coursier.ivy.{ IvyXml, IvyRepository }
import java.net.MalformedURLException
import java.net.{ MalformedURLException, URL }
import sbt.{ Resolver, CrossVersion, ModuleID }
import sbt.mavenint.SbtPomExtraProperties
@ -80,11 +80,25 @@ object FromSbt {
}
for {
(from, to) <- allMappings.toSeq
(from, to) <- allMappings
attr <- attributes
} yield from -> dep.copy(configuration = to, attributes = attr)
}
def fallbackDependencies(
allDependencies: Seq[ModuleID],
scalaVersion: String,
scalaBinaryVersion: String
): Seq[(Module, String, URL, Boolean)] =
for {
module <- allDependencies
artifact <- module.explicitArtifacts
url <- artifact.url.toSeq
} yield {
val (module0, version) = moduleVersion(module, scalaVersion, scalaBinaryVersion)
(module0, version, url, module.isChanging)
}
def project(
projectID: ModuleID,
allDependencies: Seq[ModuleID],

View File

@ -1,6 +1,8 @@
package coursier
import java.io.File
import java.net.URL
import coursier.core.Publication
import sbt.{ GetClassifiersModule, Resolver, SettingKey, TaskKey }
@ -18,6 +20,8 @@ object Keys {
val coursierCache = SettingKey[File]("coursier-cache", "")
val coursierFallbackDependencies = TaskKey[Seq[(Module, String, URL, Boolean)]]("coursier-fallback-dependencies", "")
val coursierProject = TaskKey[Project]("coursier-project", "")
val coursierProjects = TaskKey[Seq[Project]]("coursier-projects", "")
val coursierPublications = TaskKey[Seq[(String, Publication)]]("coursier-publications", "")

View File

@ -1,6 +1,7 @@
package coursier
import java.io.{ OutputStreamWriter, File }
import java.net.URL
import java.nio.file.Files
import java.util.concurrent.Executors
@ -42,6 +43,26 @@ object Tasks {
}
}
def coursierFallbackDependenciesTask: Def.Initialize[sbt.Task[Seq[(Module, String, URL, Boolean)]]] =
(
sbt.Keys.state,
sbt.Keys.thisProjectRef
).flatMap { (state, projectRef) =>
val allDependenciesTask = allDependencies.in(projectRef).get(state)
for {
allDependencies <- allDependenciesTask
} yield {
FromSbt.fallbackDependencies(
allDependencies,
scalaVersion.in(projectRef).get(state),
scalaBinaryVersion.in(projectRef).get(state)
)
}
}
def coursierProjectTask: Def.Initialize[sbt.Task[Project]] =
(
sbt.Keys.state,
@ -181,19 +202,31 @@ object Tasks {
lazy val cm = coursierSbtClassifiersModule.value
val currentProject =
if (sbtClassifiers)
FromSbt.project(
val (currentProject, fallbackDependencies) =
if (sbtClassifiers) {
val sv = scalaVersion.value
val sbv = scalaBinaryVersion.value
val proj = FromSbt.project(
cm.id,
cm.modules,
cm.configurations.map(cfg => cfg.name -> cfg.extendsConfigs.map(_.name)).toMap,
scalaVersion.value,
scalaBinaryVersion.value
sv,
sbv
)
else {
val fallbackDeps = FromSbt.fallbackDependencies(
cm.modules,
sv,
sbv
)
(proj, fallbackDeps)
} else {
val proj = coursierProject.value
val publications = coursierPublications.value
proj.copy(publications = publications)
val fallbackDeps = coursierFallbackDependencies.value
(proj.copy(publications = publications), fallbackDeps)
}
val ivySbt0 = ivySbt.value
@ -226,6 +259,24 @@ object Tasks {
FromSbt.moduleVersion(_, sv, sbv)
).toMap
var anyNonSupportedExclusionRule = false
val exclusions = excludeDependencies.value.flatMap {
rule =>
if (
rule.artifact != "*" ||
rule.configurations.nonEmpty ||
rule.crossVersion != sbt.CrossVersion.Disabled
) {
Console.err.println(s"Warning: unsupported exclusion rule $rule")
anyNonSupportedExclusionRule = true
Nil
} else
Seq((rule.organization, rule.name))
}.toSet
if (anyNonSupportedExclusionRule)
Console.err.println(s"Only supported exclusion rule fields: organization, name")
val resolvers =
if (sbtClassifiers)
coursierSbtResolvers.value
@ -236,7 +287,10 @@ object Tasks {
val startRes = Resolution(
currentProject.dependencies.map { case (_, dep) => dep }.toSet,
currentProject.dependencies.map {
case (_, dep) =>
dep.copy(exclusions = dep.exclusions ++ exclusions)
}.toSet,
filter = Some(dep => !dep.optional),
forceVersions = userForceVersions ++ forcedScalaModules(sv) ++ projects.map(_.moduleVersion)
)
@ -277,7 +331,25 @@ object Tasks {
"ivy.home" -> (new File(sys.props("user.home")).toURI.getPath + ".ivy2")
) ++ sys.props
val repositories = Seq(globalPluginsRepo, interProjectRepo) ++ resolvers.flatMap(FromSbt.repository(_, ivyProperties))
val repositories = Seq(
globalPluginsRepo,
interProjectRepo
) ++ resolvers.flatMap(
FromSbt.repository(_, ivyProperties)
) ++ {
if (fallbackDependencies.isEmpty)
Nil
else {
val map = fallbackDependencies.map {
case (mod, ver, url, changing) =>
(mod, ver) -> ((url, changing))
}.toMap
Seq(
FallbackDependenciesRepository(map)
)
}
}
def report = {
val pool = Executors.newFixedThreadPool(parallelDownloads, Strategy.DefaultDaemonThreadFactory)

View File

@ -0,0 +1,5 @@
scalaVersion := "2.11.8"
libraryDependencies += "com.github.alexarchambault" %% "argonaut-shapeless_6.1" % "1.0.0-RC1"
excludeDependencies += SbtExclusionRule("com.chuusai", "shapeless_2.11")

View File

@ -0,0 +1,11 @@
{
val pluginVersion = sys.props.getOrElse(
"plugin.version",
throw new RuntimeException(
"""|The system property 'plugin.version' is not defined.
|Specify this property using the scriptedLaunchOpts -D.""".stripMargin
)
)
addSbtPlugin("io.get-coursier" % "sbt-coursier" % pluginVersion)
}

View File

@ -0,0 +1,21 @@
import java.io.File
import java.nio.file.Files
import scala.util.Try
object Main extends App {
def classFound(clsName: String) = Try(
Thread.currentThread()
.getContextClassLoader()
.loadClass(clsName)
).toOption.nonEmpty
val shapelessFound = classFound("shapeless.HList")
val argonautShapelessFound = classFound("argonaut.derive.MkEncodeJson")
assert(argonautShapelessFound)
assert(!shapelessFound)
Files.write(new File("output").toPath, "OK".getBytes("UTF-8"))
}

View File

@ -0,0 +1,3 @@
$ delete output
> run
$ exists output

View File

@ -0,0 +1,31 @@
scalaVersion := "2.11.8"
libraryDependencies += "com.chuusai" %% "shapeless" % "2.3.41" from {
val f = file(sys.props("sbttest.base")) / "sbt-coursier" / "from" / "shapeless_2.11-2.3.0.jar"
if (!f.exists()) {
val url0 = "https://repo1.maven.org/maven2/com/chuusai/shapeless_2.11/2.3.0/shapeless_2.11-2.3.0.jar"
scala.Console.err.println(s"Fetching $url0")
val url = new java.net.URL(url0)
val is = url.openStream()
val os = new java.io.FileOutputStream(f)
var read = -1
val b = Array.fill[Byte](16*1024)(0)
while ({
read = is.read(b)
read >= 0
}) {
os.write(b, 0, read)
}
is.close()
os.close()
}
f.toURI.toString
}

View File

@ -0,0 +1,11 @@
{
val pluginVersion = sys.props.getOrElse(
"plugin.version",
throw new RuntimeException(
"""|The system property 'plugin.version' is not defined.
|Specify this property using the scriptedLaunchOpts -D.""".stripMargin
)
)
addSbtPlugin("io.get-coursier" % "sbt-coursier" % pluginVersion)
}

View File

@ -0,0 +1,13 @@
import java.io.File
import java.nio.file.Files
import shapeless._
object Main extends App {
case class CC(s: String)
val cc = CC("OK")
val l = Generic[CC].to(cc)
val msg = l.head
Files.write(new File("output").toPath, msg.getBytes("UTF-8"))
}

View File

@ -0,0 +1,3 @@
$ delete output
> run
$ exists output

View File

@ -0,0 +1 @@
scalaVersion := "2.11.8"

View File

@ -0,0 +1,11 @@
{
val pluginVersion = sys.props.getOrElse(
"plugin.version",
throw new RuntimeException(
"""|The system property 'plugin.version' is not defined.
|Specify this property using the scriptedLaunchOpts -D.""".stripMargin
)
)
addSbtPlugin("io.get-coursier" % "sbt-coursier" % pluginVersion)
}

View File

@ -0,0 +1,6 @@
import java.io.File
import java.nio.file.Files
object Main extends App {
Files.write(new File("output").toPath, "OK".getBytes("UTF-8"))
}

View File

@ -0,0 +1,3 @@
$ delete output
> run
$ exists output

View File

@ -6,3 +6,4 @@ addSbtPlugin("org.tpolecat" % "tut-plugin" % "0.4.0")
addSbtPlugin("com.github.alexarchambault" % "coursier-sbt-plugin" % "1.0.0-M8")
addSbtPlugin("com.typesafe.sbt" % "sbt-proguard" % "0.2.2")
addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "0.1.8")
libraryDependencies += "org.scala-sbt" % "scripted-plugin" % sbtVersion.value