Skip to content

Commit

Permalink
Fix NoSuchMethodError due to internal API breakage in sbt >= 1.4
Browse files Browse the repository at this point in the history
Using runtime reflection, we can avoid having the concrete prototype
of the `defaultScreen` and `withScreenLogger` methods encoded in byte
code.
  • Loading branch information
avdv committed Oct 16, 2020
1 parent deed23e commit 57e957f
Showing 1 changed file with 24 additions and 4 deletions.
28 changes: 24 additions & 4 deletions src/main/scala/sbthyperlink/HyperlinkPlugin.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import sbt.{ Def, _ }
import sbt.Keys._
import sbt.plugins.CorePlugin
import sbt.internal._
import sbt.internal.util.MainAppender._
import sbt.internal.util.MainAppender
import sbt.internal.util.ConsoleAppender

import scala.util.matching.Regex
Expand Down Expand Up @@ -84,10 +84,30 @@ object HyperlinkPlugin extends AutoPlugin {
hyperlinkRegex := Default.regex(baseDirectory.value),
hyperlinkAction := FileAction,
logManager := {
LogManager.withScreenLogger {
// we use internal sbt APIs, which are incompatible between < 1.4 and >= 1.4
// see https://github.com/sbt/sbt/issues/5931 and https://github.com/sbt/sbt/pull/5731
// work-around using reflection
import scala.reflect.runtime.{ universe => ru }

val mirror = ru.runtimeMirror(getClass.getClassLoader)
val mainAppenderType = mirror.typeOf[MainAppender.type]
val mainAppenderModuleSymbol = mainAppenderType.termSymbol.asModule
val mainAppender = mirror.reflect(mirror.reflectModule(mainAppenderModuleSymbol).instance)
val defaultScreenMethodSymbol =
mainAppenderType.decl(ru.TermName("defaultScreen")).asTerm.alternatives.collectFirst {
case m if m.asMethod.paramLists.foldLeft(0)(_ + _.size) == 1 => m.asMethod
}
val defaultScreen = mainAppender.reflectMethod(defaultScreenMethodSymbol.get)

val logManagerType = mirror.typeOf[LogManager.type]
val logManagerModuleSymbol = logManagerType.termSymbol.asModule
val logManager = mirror.reflect(mirror.reflectModule(logManagerModuleSymbol).instance)
val withScreenLoggerMethodSymbol = logManagerType.decl(ru.TermName("withScreenLogger")).asMethod
val withScreenLogger = logManager.reflectMethod(withScreenLoggerMethodSymbol)

withScreenLogger({
(_: ScopedKey[_], state: State)
val extracted = Project.extract(state)
val basedir = extracted.get(baseDirectory)
val action: HyperlinkAction = extracted.get(hyperlinkAction)
val regex: Regex = extracted.get(hyperlinkRegex)

Expand All @@ -100,7 +120,7 @@ object HyperlinkPlugin extends AutoPlugin {

override def print(s: String): Unit = super.print(filter(s))
}))
}
}).asInstanceOf[LogManager]
}
)
}

0 comments on commit 57e957f

Please sign in to comment.