sbt/librarymanagement

Match errors due to changes in MavenRepository and MavenCache class hierarchy

dwijnand opened this issue · 1 comments

I'm getting these when running scripted in sbt:

[info] scala.MatchError: cache:publish-m2-local: /Users/dnw/.m2/repository (of class sbt.librarymanagement.MavenCache)
[info] 	at sbt.internal.librarymanagement.ConvertResolver$$anonfun$defaultConvert$1.applyOrElse(ConvertResolver.scala:117)
[info] 	at sbt.internal.librarymanagement.ConvertResolver$$anonfun$defaultConvert$1.applyOrElse(ConvertResolver.scala:115)
[info] 	at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:36)
[info] 	at sbt.internal.librarymanagement.ConvertResolver$.apply(ConvertResolver.scala:112)
[info] 	at sbt.internal.librarymanagement.IvySbt$$anonfun$mapResolvers$1$1.apply(Ivy.scala:279)
[info] 	at sbt.internal.librarymanagement.IvySbt$$anonfun$mapResolvers$1$1.apply(Ivy.scala:279)
[info] 	at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234)
[info] 	at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234)
[info] 	at scala.collection.Iterator$class.foreach(Iterator.scala:893)
[info] 	at scala.collection.AbstractIterator.foreach(Iterator.scala:1336)
[info] 	at scala.collection.IterableLike$class.foreach(IterableLike.scala:72)
[info] 	at scala.collection.AbstractIterable.foreach(Iterable.scala:54)
[info] 	at scala.collection.TraversableLike$class.map(TraversableLike.scala:234)
[info] 	at scala.collection.AbstractTraversable.map(Traversable.scala:104)
[info] 	at sbt.internal.librarymanagement.IvySbt$.mapResolvers$1(Ivy.scala:279)

The reason is that in the current (85e7cf6) version of lm MavenCache is no longer a subclass of MavenRepository, which is what defaultConvert is expecting.

Here's the class hierarchy in v0.13.13:

/** An instance of a remote maven repository.  Note:  This will use Aether/Maven to resolve artifacts. */
sealed case class MavenRepository(name: String, root: String) extends Resolver {
  override def toString = s"$name: $root"
  def isCache: Boolean = false
  def localIfFile: Boolean = true
  def withLocalIfFile(value: Boolean) = new MavenRepository(name, root) { override def localIfFile = value }
}

/**
 * An instance of maven CACHE directory.  You cannot treat a cache directory the same as a a remote repository because
 * the metadata is different (see Aether ML discussion).
 */
final class MavenCache(name: String, val rootFile: File) extends MavenRepository(name, rootFile.toURI.toURL.toString) {
  override val toString = s"cache:$name: ${rootFile.getAbsolutePath}"
  override def isCache: Boolean = true
}
object MavenCache {
  def apply(name: String, rootFile: File): MavenCache = new MavenCache(name, rootFile)
}

The class hierarchy that @Duhemm created:

        {
          "name": "IMavenRepository",
          "namespace": "sbt.librarymanagement",
          "target": "Scala",
          "type": "interface",
          "doc": "An instance of a remote maven repository.  Note:  This will use Aether/Maven to resolve artifacts.",
          "fields": [
            { "name": "root",        "type": "String"                                       },
            { "name": "localIfFile", "type": "boolean", "default": "true", "since": "0.0.1" }
          ],
          "types": [
            {
              "name": "MavenRepository",
              "namespace": "sbt.librarymanagement",
              "target": "Scala",
              "type": "record",
              "toString": "s\"$name: $root\""
            },
            {
              "name": "MavenCache",
              "namespace": "sbt.librarymanagement",
              "target": "Scala",
              "type": "record",
              "doc": [
                "An instance of maven CACHE directory.  You cannot treat a cache directory the same as a a remote repository because",
                "the metadata is different (see Aether ML discussion)."
              ],
              "fields": [
                { "name": "rootFile", "type": "java.io.File" }
              ],
              "extra": "def this(name: String, rootFile: java.io.File) = this(name, rootFile.toURI.toURL.toString, true, rootFile)",
              "toString": "s\"cache:$name: ${rootFile.getAbsolutePath}\"",
              "extraCompanion": "def apply(name: String, rootFile: java.io.File): MavenCache = new MavenCache(name, rootFile)"
            }
          ]
        },

ie. an IMavenRepository parent abstract class, and MavenRepository and MavenCache subclasses

There are 3 options:

  1. Keep this hierarchy, change all the code that expected MavenRepository to now expect IMavenRepository.
  2. Make MavenRepository the parent abstract class, and MavenRepo/MavenCache the leaves, change all invocations of new MavenRepository(.. to either new MavenRepo(.. or MavenRepository(..
  3. Model it in Scala, not in JSON, creating a concrete sealed MavenRepository class and a leaf final MavenCache class.

@eed3si9n what do you prefer?

Making a single record called MavenRepository, I think would simplify this mess.