From 57e957fda3ddd6eb8ab0dd2b4dd790a8367c66b8 Mon Sep 17 00:00:00 2001 From: Claudio Bley Date: Fri, 16 Oct 2020 21:24:19 +0200 Subject: [PATCH] Fix `NoSuchMethodError` due to internal API breakage in sbt >= 1.4 Using runtime reflection, we can avoid having the concrete prototype of the `defaultScreen` and `withScreenLogger` methods encoded in byte code. --- .../scala/sbthyperlink/HyperlinkPlugin.scala | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/main/scala/sbthyperlink/HyperlinkPlugin.scala b/src/main/scala/sbthyperlink/HyperlinkPlugin.scala index 79c1a02..a00df11 100644 --- a/src/main/scala/sbthyperlink/HyperlinkPlugin.scala +++ b/src/main/scala/sbthyperlink/HyperlinkPlugin.scala @@ -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 @@ -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) @@ -100,7 +120,7 @@ object HyperlinkPlugin extends AutoPlugin { override def print(s: String): Unit = super.print(filter(s)) })) - } + }).asInstanceOf[LogManager] } ) }