diff --git a/build.sbt b/build.sbt index a34ca446e..9f96c390e 100644 --- a/build.sbt +++ b/build.sbt @@ -102,7 +102,10 @@ lazy val lmCore = (project in file("core")) // method open(java.net.URL)java.net.HttpURLConnection in object sbt.librarymanagement.Http does not have a correspondent in current version // Was private[sbt] and manually checked to be unused in Zinc or sbt ProblemFilters.exclude[DirectMissingMethodProblem]("sbt.librarymanagement.Http.open"), - + // New methods added to LM API + ProblemFilters.exclude[ReversedMissingMethodProblem]("sbt.librarymanagement.ModuleDescriptor.moduleSettings"), + // New methods added to LM API + ProblemFilters.exclude[ReversedMissingMethodProblem]("sbt.librarymanagement.ModuleDescriptor.extraInputHash"), // method globalLockIsoString()sjsonnew.IsoString in trait sbt.internal.librarymanagement.formats.GlobalLockFormat is present only in current version // method xsbtiLoggerIsoString()sjsonnew.IsoString in trait sbt.internal.librarymanagement.formats.LoggerFormat is present only in current version // These only fail in Scala 2.11 diff --git a/core/src/main/scala/sbt/librarymanagement/LibraryManagementInterface.scala b/core/src/main/scala/sbt/librarymanagement/LibraryManagementInterface.scala index 6afc27e2d..33c72c55f 100644 --- a/core/src/main/scala/sbt/librarymanagement/LibraryManagementInterface.scala +++ b/core/src/main/scala/sbt/librarymanagement/LibraryManagementInterface.scala @@ -81,4 +81,14 @@ trait ModuleDescriptor { * if any. */ def scalaModuleInfo: Option[ScalaModuleInfo] + + /** + * The input parameters used to construct the `ModuleSettings`. + */ + def moduleSettings: ModuleSettings + + /** + * Hash for extra parameter that were not captured as `moduleSettings`. + */ + def extraInputHash: Long } diff --git a/ivy/src/main/scala/sbt/internal/librarymanagement/Ivy.scala b/ivy/src/main/scala/sbt/internal/librarymanagement/Ivy.scala index 86c1ef5f2..dcf5f3327 100644 --- a/ivy/src/main/scala/sbt/internal/librarymanagement/Ivy.scala +++ b/ivy/src/main/scala/sbt/internal/librarymanagement/Ivy.scala @@ -36,10 +36,12 @@ import org.apache.ivy.util.extendable.ExtendableItem import org.apache.ivy.util.url._ import scala.xml.NodeSeq import scala.collection.mutable -import sbt.util.Logger +import scala.util.{ Success, Failure } +import sbt.util._ import sbt.librarymanagement.{ ModuleDescriptorConfiguration => InlineConfiguration, _ } import sbt.librarymanagement.ivy._ import sbt.librarymanagement.syntax._ + import IvyInternalDefaults._ import Resolver.PluginPattern import ivyint.{ @@ -49,6 +51,8 @@ import ivyint.{ SbtDefaultDependencyDescriptor, GigahorseUrlHandler } +import sjsonnew.JsonFormat +import sjsonnew.support.murmurhash.Hasher final class IvySbt(val configuration: IvyConfiguration) { self => /* @@ -336,6 +340,73 @@ final class IvySbt(val configuration: IvyConfiguration) { self => ) } private def toURL(file: File) = file.toURI.toURL + + // Todo: We just need writing side of this codec. We can clean up the reads. + private[sbt] object AltLibraryManagementCodec extends IvyLibraryManagementCodec { + import sbt.io.Hash + type InlineIvyHL = (Option[IvyPaths], Vector[Resolver], Vector[Resolver], Vector[ + ModuleConfiguration], Vector[String], Boolean) + def inlineIvyToHL(i: InlineIvyConfiguration): InlineIvyHL = + (i.paths, i.resolvers, i.otherResolvers, i.moduleConfigurations, + i.checksums, i.managedChecksums) + + type ExternalIvyHL = (Option[PlainFileInfo], Array[Byte]) + def externalIvyToHL(e: ExternalIvyConfiguration): ExternalIvyHL = + (e.baseDirectory.map(FileInfo.exists.apply), + e.uri.map(Hash.contentsIfLocal).getOrElse(Array.empty)) + + // Redefine to use a subset of properties, that are serialisable + override implicit lazy val InlineIvyConfigurationFormat: JsonFormat[InlineIvyConfiguration] = { + def hlToInlineIvy(i: InlineIvyHL): InlineIvyConfiguration = { + val (paths, resolvers, otherResolvers, moduleConfigurations, checksums, managedChecksums) = i + InlineIvyConfiguration() + .withPaths(paths) + .withResolvers(resolvers) + .withOtherResolvers(otherResolvers) + .withModuleConfigurations(moduleConfigurations) + .withManagedChecksums(managedChecksums) + .withChecksums(checksums) + } + projectFormat[InlineIvyConfiguration, InlineIvyHL](inlineIvyToHL, hlToInlineIvy) + } + + // Redefine to use a subset of properties, that are serialisable + override implicit lazy val ExternalIvyConfigurationFormat + : JsonFormat[ExternalIvyConfiguration] = { + def hlToExternalIvy(e: ExternalIvyHL): ExternalIvyConfiguration = { + val (baseDirectory, _) = e + ExternalIvyConfiguration( + None, + Some(NullLogger), + UpdateOptions(), + baseDirectory.map(_.file), + None /* the original uri is destroyed.. */, + Vector.empty + ) + } + projectFormat[ExternalIvyConfiguration, ExternalIvyHL](externalIvyToHL, hlToExternalIvy) + } + + // Redefine to switch to unionFormat + override implicit lazy val IvyConfigurationFormat: JsonFormat[IvyConfiguration] = + unionFormat2[IvyConfiguration, InlineIvyConfiguration, ExternalIvyConfiguration] + + object NullLogger extends sbt.internal.util.BasicLogger { + override def control(event: sbt.util.ControlEvent.Value, message: ⇒ String): Unit = () + override def log(level: Level.Value, message: ⇒ String): Unit = () + override def logAll(events: Seq[sbt.util.LogEvent]): Unit = () + override def success(message: ⇒ String): Unit = () + override def trace(t: ⇒ Throwable): Unit = () + } + } + + def extraInputHash: Long = { + import AltLibraryManagementCodec._ + Hasher.hash(owner.configuration) match { + case Success(keyHash) => keyHash.toLong + case Failure(_) => 0L + } + } } }