Write Ivy related files in resolution cache for publish to be fine

This commit is contained in:
Alexandre Archambault 2015-12-30 01:34:44 +01:00
parent d33ab9da26
commit 138d565187
5 changed files with 165 additions and 6 deletions

View File

@ -23,6 +23,7 @@ object CoursierPlugin extends AutoPlugin {
val coursierCache = Keys.coursierCache
val coursierProject = Keys.coursierProject
val coursierProjects = Keys.coursierProjects
val coursierPublications = Keys.coursierPublications
val coursierSbtClassifiersModule = Keys.coursierSbtClassifiersModule
}
@ -44,6 +45,7 @@ object CoursierPlugin extends AutoPlugin {
updateSbtClassifiers in Defaults.TaskGlobal <<= Tasks.updateTask(withClassifiers = true, sbtClassifiers = true),
coursierProject <<= Tasks.coursierProjectTask,
coursierProjects <<= Tasks.coursierProjectsTask,
coursierPublications <<= Tasks.coursierPublicationsTask,
coursierSbtClassifiersModule <<= classifiersModule in updateSbtClassifiers
)

View File

@ -10,10 +10,18 @@ object FromSbt {
moduleId: ModuleID,
scalaVersion: => String,
scalaBinaryVersion: => String
): String = moduleId.crossVersion match {
case CrossVersion.Disabled => moduleId.name
case f: CrossVersion.Full => moduleId.name + "_" + f.remapVersion(scalaVersion)
case f: CrossVersion.Binary => moduleId.name + "_" + f.remapVersion(scalaBinaryVersion)
): String =
sbtCrossVersionName(moduleId.name, moduleId.crossVersion, scalaVersion, scalaBinaryVersion)
def sbtCrossVersionName(
name: String,
crossVersion: CrossVersion,
scalaVersion: => String,
scalaBinaryVersion: => String
): String = crossVersion match {
case CrossVersion.Disabled => name
case f: CrossVersion.Full => name + "_" + f.remapVersion(scalaVersion)
case f: CrossVersion.Binary => name + "_" + f.remapVersion(scalaBinaryVersion)
}
def mappings(mapping: String): Seq[(String, String)] =

View File

@ -1,6 +1,7 @@
package coursier
import java.io.File
import coursier.core.Publication
import sbt.{ GetClassifiersModule, Resolver, SettingKey, TaskKey }
object Keys {
@ -19,6 +20,7 @@ object Keys {
val coursierProject = TaskKey[(Project, Seq[(String, Seq[Artifact])])]("coursier-project", "")
val coursierProjects = TaskKey[Seq[(Project, Seq[(String, Seq[Artifact])])]]("coursier-projects", "")
val coursierPublications = TaskKey[Seq[(String, Publication)]]("coursier-publications", "")
val coursierSbtClassifiersModule = TaskKey[GetClassifiersModule]("coursier-sbt-classifiers-module", "")
}

View File

@ -0,0 +1,64 @@
package coursier
import scala.xml.{ Node, PrefixedAttribute }
object MakeIvyXml {
def apply(project: Project): Node = {
val baseInfoAttrs = <x
organisation={project.module.organization}
module={project.module.name}
revision={project.version}
/>.attributes
val infoAttrs = project.module.attributes.foldLeft(baseInfoAttrs) {
case (acc, (k, v)) =>
new PrefixedAttribute("e", k, v, acc)
}
val licenseElems = project.info.licenses.map {
case (name, urlOpt) =>
var n = <license name={name} />
for (url <- urlOpt)
n = n % <x url={url} />.attributes
n
}
val infoElem = {
<info>
{licenseElems}
<description>{project.info.description}</description>
</info>
} % infoAttrs
val confElems = project.configurations.toVector.map {
case (name, extends0) =>
var n = <conf name={name} visibility="public" description="" />
if (extends0.nonEmpty)
n = n % <x extends={extends0.mkString(",")} />.attributes
n
}
val publicationElems = project.publications.map {
case (conf, pub) =>
var n = <artifact name={pub.name} type={pub.`type`} ext={pub.ext} conf={conf} />
if (pub.classifier.nonEmpty)
n = n % <x e:classifier={pub.classifier} />.attributes
n
}
val dependencyElems = project.dependencies.toVector.map {
case (conf, dep) =>
<dependency org={dep.module.organization} name={dep.module.name} rev={dep.version} conf={s"$conf->${dep.configuration}"} />
}
<ivy-module version="2.0" xmlns:e="http://ant.apache.org/ivy/extra">
{infoElem}
<configurations>{confElems}</configurations>
<publications>{publicationElems}</publications>
<dependencies>{dependencyElems}</dependencies>
</ivy-module>
}
}

View File

@ -1,16 +1,21 @@
package coursier
import java.io.{ OutputStreamWriter, File }
import java.nio.file.Files
import java.util.concurrent.Executors
import coursier.core.Publication
import coursier.ivy.IvyRepository
import coursier.Keys._
import coursier.Structure._
import org.apache.ivy.core.module.id.ModuleRevisionId
import sbt.{ UpdateReport, Classpaths, Resolver, Def }
import sbt.Configurations.{ Compile, Test }
import sbt.Keys._
import scala.collection.mutable
import scala.collection.JavaConverters._
import scalaz.{ \/-, -\/ }
import scalaz.concurrent.{ Task, Strategy }
@ -76,6 +81,51 @@ object Tasks {
coursierProject.forAllProjects(state, projects).map(_.values.toVector)
}
def coursierPublicationsTask: Def.Initialize[sbt.Task[Seq[(String, Publication)]]] =
(
sbt.Keys.state,
sbt.Keys.thisProjectRef,
sbt.Keys.projectID,
sbt.Keys.scalaVersion,
sbt.Keys.scalaBinaryVersion
).map { (state, projectRef, projId, sv, sbv) =>
val packageTasks = Seq(packageBin, packageSrc, packageDoc)
val configs = Seq(Compile, Test)
val sbtArtifacts =
for {
pkgTask <- packageTasks
config <- configs
} yield {
val publish = publishArtifact.in(projectRef).in(pkgTask).in(config).getOrElse(state, false)
if (publish)
Option(artifact.in(projectRef).in(pkgTask).in(config).getOrElse(state, null))
.map(config.name -> _)
else
None
}
sbtArtifacts.collect {
case Some((config, artifact)) =>
val name = FromSbt.sbtCrossVersionName(
artifact.name,
projId.crossVersion,
sv,
sbv
)
val publication = Publication(
name,
artifact.`type`,
artifact.extension,
artifact.classifier.getOrElse("")
)
config -> publication
}
}
// FIXME More things should possibly be put here too (resolvers, etc.)
private case class CacheKey(
resolution: Resolution,
@ -112,10 +162,25 @@ object Tasks {
scalaBinaryVersion.value
)
else {
val (p, _) = coursierProject.value
p
val (proj, _) = coursierProject.value
val publications = coursierPublications.value
proj.copy(publications = publications)
}
val ivySbt0 = ivySbt.value
val ivyCacheManager = ivySbt0.withIvy(streams.value.log)(ivy =>
ivy.getResolutionCacheManager
)
val ivyModule = ModuleRevisionId.newInstance(
currentProject.module.organization,
currentProject.module.name,
currentProject.version,
currentProject.module.attributes.asJava
)
val cacheIvyFile = ivyCacheManager.getResolvedIvyFileInCache(ivyModule)
val cacheIvyPropertiesFile = ivyCacheManager.getResolvedIvyPropertiesInCache(ivyModule)
val projects = coursierProjects.value
val parallelDownloads = coursierParallelDownloads.value
@ -140,6 +205,22 @@ object Tasks {
forceVersions = projects.map { case (proj, _) => proj.moduleVersion }.toMap
)
// required for publish to be fine, later on
def writeIvyFiles() = {
val printer = new scala.xml.PrettyPrinter(80, 2)
val b = new StringBuilder
b ++= """<?xml version="1.0" encoding="UTF-8"?>"""
b += '\n'
b ++= printer.format(MakeIvyXml(currentProject))
cacheIvyFile.getParentFile.mkdirs()
Files.write(cacheIvyFile.toPath, b.result().getBytes("UTF-8"))
// Just writing an empty file here... Are these only used?
cacheIvyPropertiesFile.getParentFile.mkdirs()
Files.write(cacheIvyPropertiesFile.toPath, "".getBytes("UTF-8"))
}
def report = {
if (verbosity >= 1) {
println("InterProjectRepository")
@ -320,6 +401,8 @@ object Tasks {
val depsByConfig = grouped(currentProject.dependencies)
writeIvyFiles()
ToSbt.updateReport(
depsByConfig,
res,