From 73e3b43683df4a80d65b838dbe4c39a925ee9ce7 Mon Sep 17 00:00:00 2001 From: Adrien Piquerez Date: Tue, 14 Nov 2023 11:43:12 +0100 Subject: [PATCH] Introduce util-core to cross-compile util-logging --- build.sbt | 18 +++++++-- .../sbt/internal/util/StringTypeTag.scala | 38 +++++++++++++++++++ .../sbt/internal/util}/StringTypeTag.scala | 2 +- .../main/scala/sbt/internal/util/Util.scala | 9 ----- .../sbt/internal/util/ManagedLogger.scala | 8 +--- .../src/main/scala/sbt/util/LogExchange.scala | 22 +++-------- 6 files changed, 61 insertions(+), 36 deletions(-) create mode 100644 internal/util-core/src/main/scala-2.13/sbt/internal/util/StringTypeTag.scala rename {core-macros/src/main/scala/sbt/internal/util/appmacro => internal/util-core/src/main/scala-3/sbt/internal/util}/StringTypeTag.scala (96%) rename {util-collection => internal/util-core}/src/main/scala/sbt/internal/util/Util.scala (87%) diff --git a/build.sbt b/build.sbt index d23046faf..90d63ab78 100644 --- a/build.sbt +++ b/build.sbt @@ -257,12 +257,11 @@ lazy val bundledLauncherProj = /* ** subproject declarations ** */ val collectionProj = (project in file("util-collection")) - .dependsOn(utilPosition) + .dependsOn(utilPosition, utilCore) .settings( name := "Collections", testedBaseSettings, utilCommonSettings, - Util.keywordsSettings, libraryDependencies ++= Seq(sjsonNewScalaJson.value), libraryDependencies ++= (CrossVersion.partialVersion(scalaVersion.value) match { case Some((2, major)) if major <= 12 => Seq() @@ -335,9 +334,22 @@ lazy val utilPosition = (project in file("internal") / "util-position") utilMimaSettings, ) +lazy val utilCore = project.in(file("internal") / "util-core") + .settings( + utilCommonSettings, + name := "Util Core", + libraryDependencies ++= { + if (scalaBinaryVersion.value.startsWith("2")) { + Seq("org.scala-lang" % "scala-reflect" % scalaVersion.value) + } else Seq.empty + }, + Util.keywordsSettings, + utilMimaSettings + ) + lazy val utilLogging = (project in file("internal") / "util-logging") .enablePlugins(ContrabandPlugin, JsonCodecPlugin) - .dependsOn(utilInterface, collectionProj, coreMacrosProj) + .dependsOn(utilInterface, utilCore) .settings( utilCommonSettings, name := "Util Logging", diff --git a/internal/util-core/src/main/scala-2.13/sbt/internal/util/StringTypeTag.scala b/internal/util-core/src/main/scala-2.13/sbt/internal/util/StringTypeTag.scala new file mode 100644 index 000000000..d9abff119 --- /dev/null +++ b/internal/util-core/src/main/scala-2.13/sbt/internal/util/StringTypeTag.scala @@ -0,0 +1,38 @@ +/* + * sbt + * Copyright 2023, Scala center + * Copyright 2011 - 2022, Lightbend, Inc. + * Copyright 2008 - 2010, Mark Harrah + * Licensed under Apache License 2.0 (see LICENSE) + */ + +package sbt.internal.util + +import scala.language.experimental.macros +import scala.reflect.macros.blackbox + +/** This is used to carry type information in JSON. */ +final case class StringTypeTag[A](key: String) { + override def toString: String = key +} + +object StringTypeTag { + + /** Generates a StringTypeTag for any type at compile time. */ + implicit def fast[A]: StringTypeTag[A] = macro impl[A] + + def impl[A: c.WeakTypeTag](c: blackbox.Context): c.Tree = { + import c.universe._ + val tpe = weakTypeOf[A] + def typeToString(tpe: Type): String = tpe match { + case TypeRef(_, sym, args) if args.nonEmpty => + val typeCon = tpe.typeSymbol.fullName + val typeArgs = args map typeToString + s"""$typeCon[${typeArgs.mkString(",")}]""" + case _ => tpe.toString + } + + val key = Literal(Constant(typeToString(tpe))) + q"new sbt.internal.util.StringTypeTag[$tpe]($key)" + } +} diff --git a/core-macros/src/main/scala/sbt/internal/util/appmacro/StringTypeTag.scala b/internal/util-core/src/main/scala-3/sbt/internal/util/StringTypeTag.scala similarity index 96% rename from core-macros/src/main/scala/sbt/internal/util/appmacro/StringTypeTag.scala rename to internal/util-core/src/main/scala-3/sbt/internal/util/StringTypeTag.scala index a144923a9..4cc8c2981 100644 --- a/core-macros/src/main/scala/sbt/internal/util/appmacro/StringTypeTag.scala +++ b/internal/util-core/src/main/scala-3/sbt/internal/util/StringTypeTag.scala @@ -5,7 +5,7 @@ * Licensed under Apache License 2.0 (see LICENSE) */ -package sbt.internal.util.appmacro +package sbt.internal.util final class StringTypeTag[A](val key: String): override def toString(): String = key diff --git a/util-collection/src/main/scala/sbt/internal/util/Util.scala b/internal/util-core/src/main/scala/sbt/internal/util/Util.scala similarity index 87% rename from util-collection/src/main/scala/sbt/internal/util/Util.scala rename to internal/util-core/src/main/scala/sbt/internal/util/Util.scala index 643f52ea7..8dbfb60f4 100644 --- a/util-collection/src/main/scala/sbt/internal/util/Util.scala +++ b/internal/util-core/src/main/scala/sbt/internal/util/Util.scala @@ -9,15 +9,9 @@ package sbt.internal.util import java.util.Locale -import scala.reflect.macros.blackbox -import scala.language.experimental.macros - object Util { def makeList[T](size: Int, value: T): List[T] = List.fill(size)(value) - // def separateE[A, B](ps: Seq[Either[A, B]]): (Seq[A], Seq[B]) = - // separate(ps)(Types.idFun) - def separate[T, A, B](ps: Seq[T])(f: T => Either[A, B]): (Seq[A], Seq[B]) = { val (a, b) = ps.foldLeft((Nil: Seq[A], Nil: Seq[B]))((xs, y) => prependEither(xs, f(y))) (a.reverse, b.reverse) @@ -74,7 +68,4 @@ object Util { implicit class AnyOps[A](private val value: A) extends AnyVal { def some: Option[A] = (Some(value): Option[A]) } - // class Macro(val c: blackbox.Context) { - // def ignore(f: c.Tree): c.Expr[Unit] = c.universe.reify({ c.Expr[Any](f).splice; () }) - // } } diff --git a/internal/util-logging/src/main/scala/sbt/internal/util/ManagedLogger.scala b/internal/util-logging/src/main/scala/sbt/internal/util/ManagedLogger.scala index fd611e655..3c9d90643 100644 --- a/internal/util-logging/src/main/scala/sbt/internal/util/ManagedLogger.scala +++ b/internal/util-logging/src/main/scala/sbt/internal/util/ManagedLogger.scala @@ -9,9 +9,8 @@ package sbt.internal.util import sbt.internal.util.codec.JsonProtocol._ import sbt.util._ -import scala.reflect.runtime.universe.TypeTag import sjsonnew.JsonFormat -import sbt.internal.util.appmacro.StringTypeTag +import sbt.internal.util.StringTypeTag private[sbt] trait MiniLogger { def log[T](level: Level.Value, message: ObjectEvent[T]): Unit @@ -44,10 +43,7 @@ class ManagedLogger( // send special event for success since it's not a real log level override def success(message: => String): Unit = { if (terminal.fold(true)(_.isSuccessEnabled)) { - infoEvent[SuccessEvent](SuccessEvent(message))( - implicitly[JsonFormat[SuccessEvent]], - StringTypeTag[SuccessEvent], - ) + infoEvent[SuccessEvent](SuccessEvent(message)) } } diff --git a/internal/util-logging/src/main/scala/sbt/util/LogExchange.scala b/internal/util-logging/src/main/scala/sbt/util/LogExchange.scala index 507b7674a..5d63b2418 100644 --- a/internal/util-logging/src/main/scala/sbt/util/LogExchange.scala +++ b/internal/util-logging/src/main/scala/sbt/util/LogExchange.scala @@ -12,7 +12,7 @@ import org.apache.logging.log4j.core.layout.PatternLayout import org.apache.logging.log4j.core.{ LoggerContext => XLoggerContext } import org.apache.logging.log4j.{ LogManager => XLogManager } import sbt.internal.util.{ Appender, ManagedLogger, TraceEvent, SuccessEvent, Util } -import sbt.internal.util.appmacro.StringTypeTag +import sbt.internal.util.StringTypeTag import java.util.concurrent.ConcurrentHashMap import scala.collection.concurrent @@ -44,23 +44,14 @@ sealed abstract class LogExchange { () } - // Construct these StringTypeTags manually, because they're used at the very startup of sbt - // and we'll try not to initialize the universe by using the StringTypeTag.apply that requires a TypeTag - // A better long-term solution could be to make StringTypeTag.apply a macro. - lazy val stringTypeTagThrowable = StringTypeTag.manually[Throwable]("java.lang.Throwable") - lazy val stringTypeTagTraceEvent = - StringTypeTag.manually[TraceEvent]("sbt.internal.util.TraceEvent") - lazy val stringTypeTagSuccessEvent = - StringTypeTag.manually[SuccessEvent]("sbt.internal.util.SuccessEvent") - private[sbt] def initStringCodecs(): Unit = { import sbt.internal.util.codec.SuccessEventShowLines._ import sbt.internal.util.codec.ThrowableShowLines._ import sbt.internal.util.codec.TraceEventShowLines._ - registerStringCodecByStringTypeTag(stringTypeTagThrowable) - registerStringCodecByStringTypeTag(stringTypeTagTraceEvent) - registerStringCodecByStringTypeTag(stringTypeTagSuccessEvent) + registerStringCodec[Throwable] + registerStringCodec[TraceEvent] + registerStringCodec[SuccessEvent] } // This is a dummy layout to avoid casting error during PatternLayout.createDefaultLayout() @@ -86,11 +77,8 @@ sealed abstract class LogExchange { stringCodecs.getOrElseUpdate(tag, v).asInstanceOf[ShowLines[A]] private[sbt] def registerStringCodec[A: ShowLines: StringTypeTag]: Unit = { - registerStringCodecByStringTypeTag(implicitly[StringTypeTag[A]]) - } - - private[sbt] def registerStringCodecByStringTypeTag[A: ShowLines](tag: StringTypeTag[A]): Unit = { val ev = implicitly[ShowLines[A]] + val tag = implicitly[StringTypeTag[A]] val _ = getOrElseUpdateStringCodec(tag.key, ev) }