From 138d565187a8a5e320f297eb338d5320f57d5be9 Mon Sep 17 00:00:00 2001 From: Alexandre Archambault Date: Wed, 30 Dec 2015 01:34:44 +0100 Subject: [PATCH] Write Ivy related files in resolution cache for publish to be fine --- .../main/scala/coursier/CoursierPlugin.scala | 2 + plugin/src/main/scala/coursier/FromSbt.scala | 16 +++- plugin/src/main/scala/coursier/Keys.scala | 2 + .../src/main/scala/coursier/MakeIvyXml.scala | 64 ++++++++++++++ plugin/src/main/scala/coursier/Tasks.scala | 87 ++++++++++++++++++- 5 files changed, 165 insertions(+), 6 deletions(-) create mode 100644 plugin/src/main/scala/coursier/MakeIvyXml.scala diff --git a/plugin/src/main/scala/coursier/CoursierPlugin.scala b/plugin/src/main/scala/coursier/CoursierPlugin.scala index cd9e4ebc3..7d617f7f4 100644 --- a/plugin/src/main/scala/coursier/CoursierPlugin.scala +++ b/plugin/src/main/scala/coursier/CoursierPlugin.scala @@ -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 ) diff --git a/plugin/src/main/scala/coursier/FromSbt.scala b/plugin/src/main/scala/coursier/FromSbt.scala index ee4940471..0611e2ed2 100644 --- a/plugin/src/main/scala/coursier/FromSbt.scala +++ b/plugin/src/main/scala/coursier/FromSbt.scala @@ -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)] = diff --git a/plugin/src/main/scala/coursier/Keys.scala b/plugin/src/main/scala/coursier/Keys.scala index 6fa28d804..3ae648fe3 100644 --- a/plugin/src/main/scala/coursier/Keys.scala +++ b/plugin/src/main/scala/coursier/Keys.scala @@ -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", "") } diff --git a/plugin/src/main/scala/coursier/MakeIvyXml.scala b/plugin/src/main/scala/coursier/MakeIvyXml.scala new file mode 100644 index 000000000..405e69af4 --- /dev/null +++ b/plugin/src/main/scala/coursier/MakeIvyXml.scala @@ -0,0 +1,64 @@ +package coursier + +import scala.xml.{ Node, PrefixedAttribute } + +object MakeIvyXml { + + def apply(project: Project): Node = { + + val baseInfoAttrs = .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 = + for (url <- urlOpt) + n = n % .attributes + n + } + + val infoElem = { + + {licenseElems} + {project.info.description} + + } % infoAttrs + + val confElems = project.configurations.toVector.map { + case (name, extends0) => + var n = + if (extends0.nonEmpty) + n = n % .attributes + n + } + + val publicationElems = project.publications.map { + case (conf, pub) => + var n = + if (pub.classifier.nonEmpty) + n = n % .attributes + n + } + + val dependencyElems = project.dependencies.toVector.map { + case (conf, dep) => + ${dep.configuration}"} /> + } + + + {infoElem} + {confElems} + {publicationElems} + {dependencyElems} + + } + +} diff --git a/plugin/src/main/scala/coursier/Tasks.scala b/plugin/src/main/scala/coursier/Tasks.scala index 1e6290565..6a079ba00 100644 --- a/plugin/src/main/scala/coursier/Tasks.scala +++ b/plugin/src/main/scala/coursier/Tasks.scala @@ -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 ++= """""" + 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,