From 3c46bc5a500258ea1a79cf3b8e1ffce1801b1f34 Mon Sep 17 00:00:00 2001 From: "Taro L. Saito" Date: Sat, 20 Apr 2024 14:53:13 -0700 Subject: [PATCH 01/16] Adjust for sbt test interface --- .../scala-3/java/util/logging/Level.scala | 18 ++++++ .../scala-3/java/util/logging/Logger.scala | 60 +++++++++++++++++++ .../{scala => scala-3}/wvlet/log/LogEnv.scala | 0 .../wvlet/log/LogTimestampFormatter.scala | 0 .../scala-3/native-test/NativeJUnit.scala | 8 +++ airspec/build.sbt | 3 +- .../wvlet/airspec/runner/AirSpecLogger.scala | 17 +++--- .../airspec/runner/AirSpecSbtRunner.scala | 6 +- .../wvlet/airspec/runner/AirSpecTask.scala | 6 +- 9 files changed, 106 insertions(+), 12 deletions(-) create mode 100644 airframe-log/.native/src/main/scala-3/java/util/logging/Level.scala create mode 100644 airframe-log/.native/src/main/scala-3/java/util/logging/Logger.scala rename airframe-log/.native/src/main/{scala => scala-3}/wvlet/log/LogEnv.scala (100%) rename airframe-log/.native/src/main/{scala => scala-3}/wvlet/log/LogTimestampFormatter.scala (100%) create mode 100644 airspec/.native/src/test/scala-3/native-test/NativeJUnit.scala diff --git a/airframe-log/.native/src/main/scala-3/java/util/logging/Level.scala b/airframe-log/.native/src/main/scala-3/java/util/logging/Level.scala new file mode 100644 index 0000000000..3c6e49c0bd --- /dev/null +++ b/airframe-log/.native/src/main/scala-3/java/util/logging/Level.scala @@ -0,0 +1,18 @@ +package java.util.logging + + +case class Level(name: String, value: Int) extends Ordered[Level] { + override def compare(other: Level): Int = value.compare(other.value) +} + +object Level: + val OFF = Level("OFF", 0) + val SEVERE = Level("SEVERE", 1000) + val WARNING = Level("WARNING", 900) + val INFO = Level("INFO", 800) + val CONFIG = Level("CONFIG", 700) + val FINE = Level("FINE", 500) + val FINER = Level("FINER", 400) + val FINEST = Level("FINEST", 300) + val ALL = Level("ALL", Integer.MIN_VALUE) + diff --git a/airframe-log/.native/src/main/scala-3/java/util/logging/Logger.scala b/airframe-log/.native/src/main/scala-3/java/util/logging/Logger.scala new file mode 100644 index 0000000000..fd2264cd2b --- /dev/null +++ b/airframe-log/.native/src/main/scala-3/java/util/logging/Logger.scala @@ -0,0 +1,60 @@ +package java.util.logging + + +abstract class Handler + +class Logger(name: String) { + def log(level: Level, msg: String): Unit = { + println(s"[$level] $name: $msg") + } + + def log(record: LogRecord): Unit = { + println(s"[${record.level}] $name: ${record.msg}") + } + + def isLoggable(level: Level): Boolean = true + + def getParent(): Logger = { + null + } + + def getLevel(): Level = { + Level.INFO + } + + def setLevel(level: Level): Unit = { + /// do nothing + } + + def setUseParentHandlers(useParentHandlers: Boolean): Unit = { + /// do nothing + } + + def addHandler(h: Handler): Unit = { + + } + + def removeHandler(h: Handler): Unit = { + /// do nothing + } + + def getHandlers: Array[Handler] = Array.empty +} + +object Logger: + def getLogger(name: String): Logger = Logger(name) + + + +abstract class Formatter: + def format(record: LogRecord): String + + + +case class LogRecord(level: Level, msg: String) extends Serializable: + def setLoggerName(name: String): Unit = { + /// do nothing + } + def setThrown(e: Throwable): Unit = { + /// do nothing + } diff --git a/airframe-log/.native/src/main/scala/wvlet/log/LogEnv.scala b/airframe-log/.native/src/main/scala-3/wvlet/log/LogEnv.scala similarity index 100% rename from airframe-log/.native/src/main/scala/wvlet/log/LogEnv.scala rename to airframe-log/.native/src/main/scala-3/wvlet/log/LogEnv.scala diff --git a/airframe-log/.native/src/main/scala/wvlet/log/LogTimestampFormatter.scala b/airframe-log/.native/src/main/scala-3/wvlet/log/LogTimestampFormatter.scala similarity index 100% rename from airframe-log/.native/src/main/scala/wvlet/log/LogTimestampFormatter.scala rename to airframe-log/.native/src/main/scala-3/wvlet/log/LogTimestampFormatter.scala diff --git a/airspec/.native/src/test/scala-3/native-test/NativeJUnit.scala b/airspec/.native/src/test/scala-3/native-test/NativeJUnit.scala new file mode 100644 index 0000000000..3aa5e7d05e --- /dev/null +++ b/airspec/.native/src/test/scala-3/native-test/NativeJUnit.scala @@ -0,0 +1,8 @@ +import org.junit.Assert._ +import org.junit.Test + +class MyTest: + @Test def nativeTest(): Unit = { + println("Hello JUnit in Scala Native") + assertTrue("this assertion should pass", true) + } diff --git a/airspec/build.sbt b/airspec/build.sbt index 93bee80c93..9cab457057 100644 --- a/airspec/build.sbt +++ b/airspec/build.sbt @@ -368,7 +368,8 @@ lazy val airspec = Compile / packageBin / mappings ++= (airspecDeps.native / Compile / packageBin / mappings).value, Compile / packageSrc / mappings ++= (airspecDeps.native / Compile / packageSrc / mappings).value, libraryDependencies ++= Seq( - "org.scala-sbt" % "test-interface" % "1.0", + // "org.scala-sbt" % "test-interface" % "1.0", + "org.scala-native" %%% "test-interface" % "0.5.1" //("org.portable-scala" %%% "portable-scala-reflect" % "1.1.2").cross(CrossVersion.for3Use2_13) ) ) diff --git a/airspec/src/main/scala/wvlet/airspec/runner/AirSpecLogger.scala b/airspec/src/main/scala/wvlet/airspec/runner/AirSpecLogger.scala index c1770cc205..5c3d09614c 100644 --- a/airspec/src/main/scala/wvlet/airspec/runner/AirSpecLogger.scala +++ b/airspec/src/main/scala/wvlet/airspec/runner/AirSpecLogger.scala @@ -26,10 +26,13 @@ private[airspec] case class AirSpecEvent( taskDef: TaskDef, // If None, it's a spec testName: Option[String], - override val status: Status, - override val throwable: OptionalThrowable, + _status: Status, + _throwable: OptionalThrowable, durationNanos: Long ) extends Event { + override def status(): Status = _status + override def throwable(): OptionalThrowable = _throwable + override def fullyQualifiedName(): String = { testName.getOrElse(taskDef.fullyQualifiedName()) } @@ -94,7 +97,7 @@ private[airspec] class AirSpecLogger() extends AnsiColorPalette { } def logEvent(e: AirSpecEvent, indentLevel: Int = 0, showTestName: Boolean = true): Unit = { - val (baseColor, showStackTraces) = e.status match { + val (baseColor, showStackTraces) = e.status() match { case Status.Success => (GREEN, false) case Status.Failure => (RED, false) // Do not show the stack trace for assertion failures case Status.Error => (RED, true) @@ -122,10 +125,10 @@ private[airspec] class AirSpecLogger() extends AnsiColorPalette { s"${withColor(GRAY, " <")} ${elapsedTime}" } } - val tail = e.status match { + val tail = e.status() match { case Status.Success => "" - case _ if e.throwable.isDefined() => - val ex = e.throwable.get() + case _ if e.throwable().isDefined() => + val ex = e.throwable().get() ex match { case se: AirSpecFailureBase => s" ${statusLabel(se.statusLabel)}: ${withColor(baseColor, se.message)} ${errorLocation(se)}" @@ -138,7 +141,7 @@ private[airspec] class AirSpecLogger() extends AnsiColorPalette { info(s"${indent(indentLevel)}${prefix}${tail}") if (showStackTraces) { - val ex = wvlet.airspec.compat.findCause(e.throwable.get()) + val ex = wvlet.airspec.compat.findCause(e.throwable().get()) val stackTrace = LogFormatter.formatStacktrace(ex) error(stackTrace) } diff --git a/airspec/src/main/scala/wvlet/airspec/runner/AirSpecSbtRunner.scala b/airspec/src/main/scala/wvlet/airspec/runner/AirSpecSbtRunner.scala index a1a0b4ecb6..60c8778b96 100644 --- a/airspec/src/main/scala/wvlet/airspec/runner/AirSpecSbtRunner.scala +++ b/airspec/src/main/scala/wvlet/airspec/runner/AirSpecSbtRunner.scala @@ -19,14 +19,16 @@ import wvlet.log.{LogSupport, Logger, LogLevel} import scala.util.matching.Regex -/** +/**d * AirSpecRunner receives a list of TaskDefs from sbt, then create AirSpecTasks to execute. */ -private[airspec] class AirSpecSbtRunner(config: AirSpecConfig, val remoteArgs: Array[String], classLoader: ClassLoader) +private[airspec] class AirSpecSbtRunner(config: AirSpecConfig, _remoteArgs: Array[String], classLoader: ClassLoader) extends sbt.testing.Runner { + private lazy val taskLogger = new AirSpecLogger() override def args: Array[String] = config.args + override def remoteArgs(): Array[String] = _remoteArgs override def tasks(taskDefs: Array[TaskDef]): Array[Task] = { taskDefs diff --git a/airspec/src/main/scala/wvlet/airspec/runner/AirSpecTask.scala b/airspec/src/main/scala/wvlet/airspec/runner/AirSpecTask.scala index f3e59303b0..a5c2bbd9d2 100644 --- a/airspec/src/main/scala/wvlet/airspec/runner/AirSpecTask.scala +++ b/airspec/src/main/scala/wvlet/airspec/runner/AirSpecTask.scala @@ -27,12 +27,14 @@ import scala.concurrent.{Await, Promise} private[airspec] class AirSpecTask( config: AirSpecConfig, taskLogger: AirSpecLogger, - override val taskDef: TaskDef, + _taskDef: TaskDef, classLoader: ClassLoader ) extends sbt.testing.Task with LogSupport { override def tags(): Array[String] = Array.empty + override def taskDef(): TaskDef = _taskDef + /** * This method will be used only for Scala (JVM). This will delegate the task execution process to execute(handler, * logger, continuation) @@ -60,7 +62,7 @@ private[airspec] class AirSpecTask( ): Unit = { implicit val ec = wvlet.airspec.Compat.executionContext try { - new AirSpecTaskRunner(taskDef, config, taskLogger, eventHandler, classLoader).runTask + new AirSpecTaskRunner(taskDef(), config, taskLogger, eventHandler, classLoader).runTask .foreach(_ => continuation(Array.empty)) } catch { case e: Throwable => From 2812d7a935db31a2f6f86945be8cc21c6fc15b79 Mon Sep 17 00:00:00 2001 From: "Taro L. Saito" Date: Sat, 20 Apr 2024 14:54:31 -0700 Subject: [PATCH 02/16] add method --- .../.native/src/main/scala-3/java/util/logging/Logger.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/airframe-log/.native/src/main/scala-3/java/util/logging/Logger.scala b/airframe-log/.native/src/main/scala-3/java/util/logging/Logger.scala index fd2264cd2b..92d5bccd04 100644 --- a/airframe-log/.native/src/main/scala-3/java/util/logging/Logger.scala +++ b/airframe-log/.native/src/main/scala-3/java/util/logging/Logger.scala @@ -4,6 +4,8 @@ package java.util.logging abstract class Handler class Logger(name: String) { + def getName(): String = name + def log(level: Level, msg: String): Unit = { println(s"[$level] $name: $msg") } From 12c6ece7f73a5e646341a40c0ed41319c38c9686 Mon Sep 17 00:00:00 2001 From: "Taro L. Saito" Date: Sat, 20 Apr 2024 16:59:27 -0700 Subject: [PATCH 03/16] Add java.util.logging impl --- .../scala-3/java/util/logging/Level.scala | 2 + .../scala-3/java/util/logging/Logger.scala | 71 +++++++++++++++---- 2 files changed, 59 insertions(+), 14 deletions(-) diff --git a/airframe-log/.native/src/main/scala-3/java/util/logging/Level.scala b/airframe-log/.native/src/main/scala-3/java/util/logging/Level.scala index 3c6e49c0bd..61ea700db9 100644 --- a/airframe-log/.native/src/main/scala-3/java/util/logging/Level.scala +++ b/airframe-log/.native/src/main/scala-3/java/util/logging/Level.scala @@ -3,6 +3,8 @@ package java.util.logging case class Level(name: String, value: Int) extends Ordered[Level] { override def compare(other: Level): Int = value.compare(other.value) + def intValue(): Int = value + override def toString: String = name } object Level: diff --git a/airframe-log/.native/src/main/scala-3/java/util/logging/Logger.scala b/airframe-log/.native/src/main/scala-3/java/util/logging/Logger.scala index 92d5bccd04..81852079be 100644 --- a/airframe-log/.native/src/main/scala-3/java/util/logging/Logger.scala +++ b/airframe-log/.native/src/main/scala-3/java/util/logging/Logger.scala @@ -1,46 +1,66 @@ package java.util.logging -abstract class Handler +abstract class Handler extends AutoCloseable: + def publish(record: LogRecord): Unit + def flush(): Unit class Logger(name: String) { + private var handlers = List.empty[Handler] + private var parent: Option[Logger] = None + private var useParentHandlers = true + private var level: Option[Level] = None + def getName(): String = name def log(level: Level, msg: String): Unit = { - println(s"[$level] $name: $msg") + log(LogRecord(level, msg)) } def log(record: LogRecord): Unit = { - println(s"[${record.level}] $name: ${record.msg}") + if(isLoggable(record.level)) { + record.setLoggerName(name) + if(useParentHandlers) then + getParent().log(record) + else + handlers.foreach { h => h.publish(record) } + } } - def isLoggable(level: Level): Boolean = true + def isLoggable(level: Level): Boolean = { + val l = getLevel() + if(level.intValue() < l.intValue()) then false else true + } def getParent(): Logger = { - null + parent.getOrElse(null) } def getLevel(): Level = { - Level.INFO + level.orElse(parent.map(_.getLevel())).getOrElse(Level.INFO) + } + + def setLevel(newLevel: Level): Unit = { + level = Some(newLevel) } - def setLevel(level: Level): Unit = { - /// do nothing + def resetLogLevel(): Unit = { + level = None } def setUseParentHandlers(useParentHandlers: Boolean): Unit = { - /// do nothing + this.useParentHandlers = useParentHandlers } def addHandler(h: Handler): Unit = { - + handlers = h :: handlers } def removeHandler(h: Handler): Unit = { - /// do nothing + handlers = handlers.filter(_ != h) } - def getHandlers: Array[Handler] = Array.empty + def getHandlers: Array[Handler] = handlers.toArray } object Logger: @@ -48,15 +68,38 @@ object Logger: +object LogManager: + private var loggers = Map.empty[String, Logger] + def getLogger(name: String): Logger = { + + + loggers.getOrElse(name, { + val logger = Logger(name) + loggers += (name -> logger) + logger + }) + } + + abstract class Formatter: def format(record: LogRecord): String case class LogRecord(level: Level, msg: String) extends Serializable: + private val millis = System.currentTimeMillis() + private var loggerName = "" + private var thrown: Throwable = null + + def getMessage(): String = msg + def getMillis(): Long = millis + def getLoggerName(): String = loggerName + def getLevel(): Level = level + def getThrown(): Throwable = thrown + def setLoggerName(name: String): Unit = { - /// do nothing + this.loggerName = name } def setThrown(e: Throwable): Unit = { - /// do nothing + thrown = e } From 7a245a8b20825bed8d86794bc86771cdd6241ecc Mon Sep 17 00:00:00 2001 From: "Taro L. Saito" Date: Sat, 20 Apr 2024 17:27:31 -0700 Subject: [PATCH 04/16] Fix tests --- .../src/main/scala-3/java/util/logging/Logger.scala | 5 +++-- airspec/.js/src/main/scala/wvlet/airspec/Compat.scala | 2 ++ airspec/.jvm/src/main/scala/wvlet/airspec/Compat.scala | 4 +++- .../.native/src/main/scala-3/wvlet/airspec/Compat.scala | 7 ++++--- airspec/src/main/scala/wvlet/airspec/AirSpec.scala | 2 ++ airspec/src/main/scala/wvlet/airspec/CompatApi.scala | 2 ++ airspec/src/test/scala/examples/RxTest.scala | 5 ++++- 7 files changed, 20 insertions(+), 7 deletions(-) diff --git a/airframe-log/.native/src/main/scala-3/java/util/logging/Logger.scala b/airframe-log/.native/src/main/scala-3/java/util/logging/Logger.scala index 81852079be..bf4c0f1919 100644 --- a/airframe-log/.native/src/main/scala-3/java/util/logging/Logger.scala +++ b/airframe-log/.native/src/main/scala-3/java/util/logging/Logger.scala @@ -20,7 +20,7 @@ class Logger(name: String) { def log(record: LogRecord): Unit = { if(isLoggable(record.level)) { record.setLoggerName(name) - if(useParentHandlers) then + if(parent.nonEmpty && useParentHandlers) then getParent().log(record) else handlers.foreach { h => h.publish(record) } @@ -70,8 +70,9 @@ object Logger: object LogManager: private var loggers = Map.empty[String, Logger] - def getLogger(name: String): Logger = { + def getLogger(name: String): Logger = { + name.split("\\.") loggers.getOrElse(name, { val logger = Logger(name) diff --git a/airspec/.js/src/main/scala/wvlet/airspec/Compat.scala b/airspec/.js/src/main/scala/wvlet/airspec/Compat.scala index 92eabf455f..4e516d360a 100644 --- a/airspec/.js/src/main/scala/wvlet/airspec/Compat.scala +++ b/airspec/.js/src/main/scala/wvlet/airspec/Compat.scala @@ -27,7 +27,9 @@ import scala.util.Try /** */ private[airspec] object Compat extends CompatApi with LogSupport { + override def isScalaJVM = false override def isScalaJs = true + override def isScalaNative = false override private[airspec] val executionContext: ExecutionContext = org.scalajs.macrotaskexecutor.MacrotaskExecutor.Implicits.global diff --git a/airspec/.jvm/src/main/scala/wvlet/airspec/Compat.scala b/airspec/.jvm/src/main/scala/wvlet/airspec/Compat.scala index ce72cd176b..c33e6bb695 100644 --- a/airspec/.jvm/src/main/scala/wvlet/airspec/Compat.scala +++ b/airspec/.jvm/src/main/scala/wvlet/airspec/Compat.scala @@ -31,7 +31,9 @@ import scala.concurrent.ExecutionContext /** */ private[airspec] object Compat extends CompatApi with LogSupport { + override def isScalaJVM = true override def isScalaJs = false + override def isScalaNative = false override private[airspec] val executionContext: ExecutionContext = ExecutionContext.fromExecutorService(Executors.newCachedThreadPool(newDaemonThreadFactory("airspec-executor"))) @@ -46,7 +48,7 @@ private[airspec] object Compat extends CompatApi with LogSupport { private val group: ThreadGroup = new ThreadGroup(Thread.currentThread().getThreadGroup(), name) private val threadNumber = new AtomicInteger(1) - override def newThread(r: Runnable): Thread = { + override def newThread(r: Runnable): Thread = {Rx val threadName = s"${name}-${threadNumber.getAndIncrement()}" val thread = new Thread(group, r, threadName) thread.setName(threadName) diff --git a/airspec/.native/src/main/scala-3/wvlet/airspec/Compat.scala b/airspec/.native/src/main/scala-3/wvlet/airspec/Compat.scala index e3793237aa..aa500df6e8 100644 --- a/airspec/.native/src/main/scala-3/wvlet/airspec/Compat.scala +++ b/airspec/.native/src/main/scala-3/wvlet/airspec/Compat.scala @@ -31,7 +31,9 @@ import scala.util.{Success, Failure} /** */ private[airspec] object Compat extends CompatApi with LogSupport: + override def isScalaJVM = false override def isScalaJs = false + override def isScalaNative = true override private[airspec] val executionContext: ExecutionContext = ExecutionContext.global @@ -42,7 +44,6 @@ private[airspec] object Compat extends CompatApi with LogSupport: } private[airspec] def getFingerprint(fullyQualifiedName: String, classLoader: ClassLoader): Option[Fingerprint] = - println(s"Checking class fingerprint for ${fullyQualifiedName}") Try(findCompanionObjectOf(fullyQualifiedName, classLoader)).toOption .flatMap { case Some(spec: AirSpecSpi) => @@ -51,9 +52,9 @@ private[airspec] object Compat extends CompatApi with LogSupport: None } .orElse { - Try(classLoader.loadClass(fullyQualifiedName)).toOption + scala.scalanative.reflect.Reflect.lookupInstantiatableClass(fullyQualifiedName) .flatMap { x => - if classOf[AirSpec].isAssignableFrom(x) then Some(AirSpecClassFingerPrint) + if classOf[AirSpec].isAssignableFrom(x.runtimeClass) then Some(AirSpecClassFingerPrint) else None } } diff --git a/airspec/src/main/scala/wvlet/airspec/AirSpec.scala b/airspec/src/main/scala/wvlet/airspec/AirSpec.scala index f619dba2c8..e9b32c479e 100644 --- a/airspec/src/main/scala/wvlet/airspec/AirSpec.scala +++ b/airspec/src/main/scala/wvlet/airspec/AirSpec.scala @@ -119,7 +119,9 @@ private[airspec] trait AirSpecSpi extends AirSpecSpiCompat { protected def inCircleCI: Boolean = airspec.inCircleCI protected def inGitHubAction: Boolean = airspec.inGitHubAction + protected def isScalaJVM: Boolean = compat.isScalaJVM protected def isScalaJS: Boolean = compat.isScalaJs + protected def isScalaNative: Boolean = compat.isScalaNative protected def isScala2: Boolean = scalaMajorVersion == 2 protected def isScala3: Boolean = scalaMajorVersion == 3 diff --git a/airspec/src/main/scala/wvlet/airspec/CompatApi.scala b/airspec/src/main/scala/wvlet/airspec/CompatApi.scala index 668642ff8f..151c61d15e 100644 --- a/airspec/src/main/scala/wvlet/airspec/CompatApi.scala +++ b/airspec/src/main/scala/wvlet/airspec/CompatApi.scala @@ -22,7 +22,9 @@ import scala.concurrent.ExecutionContext * An interface for compatibility between Scala JVM and Scala.js */ trait CompatApi { + def isScalaJVM: Boolean def isScalaJs: Boolean + def isScalaNative: Boolean private[airspec] def executionContext: ExecutionContext private[airspec] def findCompanionObjectOf(fullyQualifiedName: String, classLoader: ClassLoader): Option[Any] diff --git a/airspec/src/test/scala/examples/RxTest.scala b/airspec/src/test/scala/examples/RxTest.scala index 654cd7ea8f..dd1c154b7f 100644 --- a/airspec/src/test/scala/examples/RxTest.scala +++ b/airspec/src/test/scala/examples/RxTest.scala @@ -22,10 +22,13 @@ class RxTest extends AirSpec { private val v = new AtomicBoolean(false) override def afterAll: Unit = { - v.get() shouldBe true + if(!isScalaNative) { + v.get() shouldBe true + } } test("return Rx") { + skip("Skip Rx timer test for Scala Native") Rx.intervalMillis(10).map(_ => v.set(true)) } From 9912ff436793da34bc0c6372ed877370460fee3d Mon Sep 17 00:00:00 2001 From: "Taro L. Saito" Date: Sat, 20 Apr 2024 17:29:21 -0700 Subject: [PATCH 05/16] Delete unused tests --- .../src/test/scala-3/native-test/NativeJUnit.scala | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 airspec/.native/src/test/scala-3/native-test/NativeJUnit.scala diff --git a/airspec/.native/src/test/scala-3/native-test/NativeJUnit.scala b/airspec/.native/src/test/scala-3/native-test/NativeJUnit.scala deleted file mode 100644 index 3aa5e7d05e..0000000000 --- a/airspec/.native/src/test/scala-3/native-test/NativeJUnit.scala +++ /dev/null @@ -1,8 +0,0 @@ -import org.junit.Assert._ -import org.junit.Test - -class MyTest: - @Test def nativeTest(): Unit = { - println("Hello JUnit in Scala Native") - assertTrue("this assertion should pass", true) - } From 84dafd7e1ff6bde9b152197411dc0401854bd3ca Mon Sep 17 00:00:00 2001 From: "Taro L. Saito" Date: Sat, 20 Apr 2024 17:33:19 -0700 Subject: [PATCH 06/16] Add isScalaNative --- airspec/.jvm/src/main/scala/wvlet/airspec/Compat.scala | 2 +- .../src/main/scala-3/wvlet/airspec/Compat.scala | 10 +++++----- airspec/src/main/scala/wvlet/airspec/AirSpec.scala | 4 ++-- .../scala/wvlet/airspec/runner/AirSpecLogger.scala | 2 +- .../scala/wvlet/airspec/runner/AirSpecSbtRunner.scala | 6 +++--- airspec/src/test/scala/examples/RxTest.scala | 2 +- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/airspec/.jvm/src/main/scala/wvlet/airspec/Compat.scala b/airspec/.jvm/src/main/scala/wvlet/airspec/Compat.scala index c33e6bb695..5acff92e6e 100644 --- a/airspec/.jvm/src/main/scala/wvlet/airspec/Compat.scala +++ b/airspec/.jvm/src/main/scala/wvlet/airspec/Compat.scala @@ -48,7 +48,7 @@ private[airspec] object Compat extends CompatApi with LogSupport { private val group: ThreadGroup = new ThreadGroup(Thread.currentThread().getThreadGroup(), name) private val threadNumber = new AtomicInteger(1) - override def newThread(r: Runnable): Thread = {Rx + override def newThread(r: Runnable): Thread = { val threadName = s"${name}-${threadNumber.getAndIncrement()}" val thread = new Thread(group, r, threadName) thread.setName(threadName) diff --git a/airspec/.native/src/main/scala-3/wvlet/airspec/Compat.scala b/airspec/.native/src/main/scala-3/wvlet/airspec/Compat.scala index aa500df6e8..7e0265a745 100644 --- a/airspec/.native/src/main/scala-3/wvlet/airspec/Compat.scala +++ b/airspec/.native/src/main/scala-3/wvlet/airspec/Compat.scala @@ -31,8 +31,8 @@ import scala.util.{Success, Failure} /** */ private[airspec] object Compat extends CompatApi with LogSupport: - override def isScalaJVM = false - override def isScalaJs = false + override def isScalaJVM = false + override def isScalaJs = false override def isScalaNative = true override private[airspec] val executionContext: ExecutionContext = ExecutionContext.global @@ -52,17 +52,17 @@ private[airspec] object Compat extends CompatApi with LogSupport: None } .orElse { - scala.scalanative.reflect.Reflect.lookupInstantiatableClass(fullyQualifiedName) + scala.scalanative.reflect.Reflect + .lookupInstantiatableClass(fullyQualifiedName) .flatMap { x => if classOf[AirSpec].isAssignableFrom(x.runtimeClass) then Some(AirSpecClassFingerPrint) else None } } - private[airspec] def newInstanceOf(fullyQualifiedName: String, classLoader: ClassLoader): Option[Any] = { + private[airspec] def newInstanceOf(fullyQualifiedName: String, classLoader: ClassLoader): Option[Any] = val clsOpt = scala.scalanative.reflect.Reflect.lookupInstantiatableClass(fullyQualifiedName) clsOpt.map(_.newInstance()) - } private[airspec] def withLogScanner[U](block: => U): U = try diff --git a/airspec/src/main/scala/wvlet/airspec/AirSpec.scala b/airspec/src/main/scala/wvlet/airspec/AirSpec.scala index e9b32c479e..052e9fc5da 100644 --- a/airspec/src/main/scala/wvlet/airspec/AirSpec.scala +++ b/airspec/src/main/scala/wvlet/airspec/AirSpec.scala @@ -119,8 +119,8 @@ private[airspec] trait AirSpecSpi extends AirSpecSpiCompat { protected def inCircleCI: Boolean = airspec.inCircleCI protected def inGitHubAction: Boolean = airspec.inGitHubAction - protected def isScalaJVM: Boolean = compat.isScalaJVM - protected def isScalaJS: Boolean = compat.isScalaJs + protected def isScalaJVM: Boolean = compat.isScalaJVM + protected def isScalaJS: Boolean = compat.isScalaJs protected def isScalaNative: Boolean = compat.isScalaNative protected def isScala2: Boolean = scalaMajorVersion == 2 diff --git a/airspec/src/main/scala/wvlet/airspec/runner/AirSpecLogger.scala b/airspec/src/main/scala/wvlet/airspec/runner/AirSpecLogger.scala index 5c3d09614c..8f2a3bf460 100644 --- a/airspec/src/main/scala/wvlet/airspec/runner/AirSpecLogger.scala +++ b/airspec/src/main/scala/wvlet/airspec/runner/AirSpecLogger.scala @@ -30,7 +30,7 @@ private[airspec] case class AirSpecEvent( _throwable: OptionalThrowable, durationNanos: Long ) extends Event { - override def status(): Status = _status + override def status(): Status = _status override def throwable(): OptionalThrowable = _throwable override def fullyQualifiedName(): String = { diff --git a/airspec/src/main/scala/wvlet/airspec/runner/AirSpecSbtRunner.scala b/airspec/src/main/scala/wvlet/airspec/runner/AirSpecSbtRunner.scala index 60c8778b96..88fe347baf 100644 --- a/airspec/src/main/scala/wvlet/airspec/runner/AirSpecSbtRunner.scala +++ b/airspec/src/main/scala/wvlet/airspec/runner/AirSpecSbtRunner.scala @@ -19,15 +19,15 @@ import wvlet.log.{LogSupport, Logger, LogLevel} import scala.util.matching.Regex -/**d - * AirSpecRunner receives a list of TaskDefs from sbt, then create AirSpecTasks to execute. +/** + * d AirSpecRunner receives a list of TaskDefs from sbt, then create AirSpecTasks to execute. */ private[airspec] class AirSpecSbtRunner(config: AirSpecConfig, _remoteArgs: Array[String], classLoader: ClassLoader) extends sbt.testing.Runner { private lazy val taskLogger = new AirSpecLogger() - override def args: Array[String] = config.args + override def args: Array[String] = config.args override def remoteArgs(): Array[String] = _remoteArgs override def tasks(taskDefs: Array[TaskDef]): Array[Task] = { diff --git a/airspec/src/test/scala/examples/RxTest.scala b/airspec/src/test/scala/examples/RxTest.scala index dd1c154b7f..5d5b187b0b 100644 --- a/airspec/src/test/scala/examples/RxTest.scala +++ b/airspec/src/test/scala/examples/RxTest.scala @@ -22,7 +22,7 @@ class RxTest extends AirSpec { private val v = new AtomicBoolean(false) override def afterAll: Unit = { - if(!isScalaNative) { + if (!isScalaNative) { v.get() shouldBe true } } From 48b025a9e582c9e0848eadf3585ed405b00bafd1 Mon Sep 17 00:00:00 2001 From: "Taro L. Saito" Date: Sat, 20 Apr 2024 21:15:40 -0700 Subject: [PATCH 07/16] reformat --- airspec/.js/src/main/scala/wvlet/airspec/Compat.scala | 4 ++-- airspec/.jvm/src/main/scala/wvlet/airspec/Compat.scala | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/airspec/.js/src/main/scala/wvlet/airspec/Compat.scala b/airspec/.js/src/main/scala/wvlet/airspec/Compat.scala index 4e516d360a..3ecc6c7956 100644 --- a/airspec/.js/src/main/scala/wvlet/airspec/Compat.scala +++ b/airspec/.js/src/main/scala/wvlet/airspec/Compat.scala @@ -27,8 +27,8 @@ import scala.util.Try /** */ private[airspec] object Compat extends CompatApi with LogSupport { - override def isScalaJVM = false - override def isScalaJs = true + override def isScalaJVM = false + override def isScalaJs = true override def isScalaNative = false override private[airspec] val executionContext: ExecutionContext = diff --git a/airspec/.jvm/src/main/scala/wvlet/airspec/Compat.scala b/airspec/.jvm/src/main/scala/wvlet/airspec/Compat.scala index 5acff92e6e..f17573a2fd 100644 --- a/airspec/.jvm/src/main/scala/wvlet/airspec/Compat.scala +++ b/airspec/.jvm/src/main/scala/wvlet/airspec/Compat.scala @@ -31,8 +31,8 @@ import scala.concurrent.ExecutionContext /** */ private[airspec] object Compat extends CompatApi with LogSupport { - override def isScalaJVM = true - override def isScalaJs = false + override def isScalaJVM = true + override def isScalaJs = false override def isScalaNative = false override private[airspec] val executionContext: ExecutionContext = From 073b3e22be33f659f97ed488d0e2d5ec369e4431 Mon Sep 17 00:00:00 2001 From: "Taro L. Saito" Date: Sun, 21 Apr 2024 00:46:29 -0700 Subject: [PATCH 08/16] Format timestamp --- .../wvlet/log/LogTimestampFormatter.scala | 2 +- .../scala-3/java/util/logging/Logger.scala | 39 +++++++++++-------- .../wvlet/log/LogTimestampFormatter.scala | 37 +++++++++++++++--- 3 files changed, 56 insertions(+), 22 deletions(-) diff --git a/airframe-log/.js/src/main/scala/wvlet/log/LogTimestampFormatter.scala b/airframe-log/.js/src/main/scala/wvlet/log/LogTimestampFormatter.scala index 2af28bc0ac..af7ee63ab3 100644 --- a/airframe-log/.js/src/main/scala/wvlet/log/LogTimestampFormatter.scala +++ b/airframe-log/.js/src/main/scala/wvlet/log/LogTimestampFormatter.scala @@ -3,7 +3,7 @@ package wvlet.log import scala.scalajs.js /** - * Use scalajs.js.Date to foramte timestamp + * Use scalajs.js.Date to foramt timestamps */ object LogTimestampFormatter { def formatTimestamp(timeMillis: Long): String = { diff --git a/airframe-log/.native/src/main/scala-3/java/util/logging/Logger.scala b/airframe-log/.native/src/main/scala-3/java/util/logging/Logger.scala index bf4c0f1919..7cf09dd086 100644 --- a/airframe-log/.native/src/main/scala-3/java/util/logging/Logger.scala +++ b/airframe-log/.native/src/main/scala-3/java/util/logging/Logger.scala @@ -5,9 +5,13 @@ abstract class Handler extends AutoCloseable: def publish(record: LogRecord): Unit def flush(): Unit -class Logger(name: String) { +/** + * Implements java.util.logging.Logger interface, which is not avaialble + * in Scala Native + * @param name + */ +class Logger(parent: Option[Logger], name: String) { private var handlers = List.empty[Handler] - private var parent: Option[Logger] = None private var useParentHandlers = true private var level: Option[Level] = None @@ -19,7 +23,9 @@ class Logger(name: String) { def log(record: LogRecord): Unit = { if(isLoggable(record.level)) { - record.setLoggerName(name) + if(record.getLoggerName() == null) { + record.setLoggerName(name) + } if(parent.nonEmpty && useParentHandlers) then getParent().log(record) else @@ -64,21 +70,23 @@ class Logger(name: String) { } object Logger: - def getLogger(name: String): Logger = Logger(name) - - - -object LogManager: - private var loggers = Map.empty[String, Logger] + import scala.jdk.CollectionConverters.* + private val loggerTable = new java.util.concurrent.ConcurrentHashMap[String, Logger]().asScala + private val rootLogger = Logger(None, "") def getLogger(name: String): Logger = { - name.split("\\.") - loggers.getOrElse(name, { - val logger = Logger(name) - loggers += (name -> logger) - logger - }) + loggerTable.getOrElseUpdate(name, newLogger(name)) + } + + private def newLogger(name: String): Logger = { + name match { + case null | "" => rootLogger + case other => + val parentName = name.substring(0, name.lastIndexOf('.').max(0)) + val parentLogger = getLogger(parentName) + Logger(Some(parentLogger), name) + } } @@ -86,7 +94,6 @@ abstract class Formatter: def format(record: LogRecord): String - case class LogRecord(level: Level, msg: String) extends Serializable: private val millis = System.currentTimeMillis() private var loggerName = "" diff --git a/airframe-log/.native/src/main/scala-3/wvlet/log/LogTimestampFormatter.scala b/airframe-log/.native/src/main/scala-3/wvlet/log/LogTimestampFormatter.scala index de8bb89da4..d3f060deef 100644 --- a/airframe-log/.native/src/main/scala-3/wvlet/log/LogTimestampFormatter.scala +++ b/airframe-log/.native/src/main/scala-3/wvlet/log/LogTimestampFormatter.scala @@ -1,16 +1,43 @@ package wvlet.log +import scalanative.posix.time.* +import scalanative.unsafe.* +import scalanative.unsigned.* +import scalanative.libc.stdio.* +import scalanative.libc.string.* + /** - * Use scalajs.js.Date to foramte timestamp + * Use strftime to format timestamps in Scala Native */ object LogTimestampFormatter { + + private def format(pattern: CString, timeMillis: Long): String = { + Zone { + val ttPtr = alloc[time_t]() + !ttPtr = (timeMillis / 1000).toSize + val tmPtr = alloc[tm]() + localtime_r(ttPtr, tmPtr) + val bufSize = 26.toUSize + val buf: Ptr[Byte] = alloc[Byte](bufSize) + strftime(buf, bufSize, pattern, tmPtr) + val ms = timeMillis % 1000 + + val msBuf: Ptr[Byte] = alloc[Byte](3) + sprintf(msBuf, c"%03d", ms) + strcat(buf, msBuf) + + val tzBuf: Ptr[Byte] = alloc[Byte](5) + strftime(tzBuf, 5.toUSize, c"%z", tmPtr) + strcat(buf, tzBuf) + fromCString(buf) + } + } + def formatTimestamp(timeMillis: Long): String = { - // TODO - "" + format(c"%Y-%m-%d %H:%M:%S.", timeMillis) } def formatTimestampWithNoSpaace(timeMillis: Long): String = { - // TODO - "" + format(c"%Y-%m-%dT%H:%M:%S.", timeMillis) } } From 2e1ef08a582db08afa7bd23f9d96e98152cac3b8 Mon Sep 17 00:00:00 2001 From: "Taro L. Saito" Date: Sun, 21 Apr 2024 00:52:25 -0700 Subject: [PATCH 09/16] Fix logger instantiation --- .../src/main/scala-3/java/util/logging/Logger.scala | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/airframe-log/.native/src/main/scala-3/java/util/logging/Logger.scala b/airframe-log/.native/src/main/scala-3/java/util/logging/Logger.scala index 7cf09dd086..e62b82ecf0 100644 --- a/airframe-log/.native/src/main/scala-3/java/util/logging/Logger.scala +++ b/airframe-log/.native/src/main/scala-3/java/util/logging/Logger.scala @@ -75,8 +75,15 @@ object Logger: private val rootLogger = Logger(None, "") def getLogger(name: String): Logger = { - - loggerTable.getOrElseUpdate(name, newLogger(name)) + loggerTable.get(name) match { + case Some(logger) => logger + case None => + val logger = newLogger(name) + synchronized { + loggerTable.put(name, logger) + } + logger + } } private def newLogger(name: String): Logger = { From 9b5bb4d43ffa157388bf97479c628a243e8a5710 Mon Sep 17 00:00:00 2001 From: "Taro L. Saito" Date: Sun, 21 Apr 2024 00:54:25 -0700 Subject: [PATCH 10/16] cleanup --- airspec/build.sbt | 2 -- 1 file changed, 2 deletions(-) diff --git a/airspec/build.sbt b/airspec/build.sbt index 9cab457057..1ccea48b37 100644 --- a/airspec/build.sbt +++ b/airspec/build.sbt @@ -368,9 +368,7 @@ lazy val airspec = Compile / packageBin / mappings ++= (airspecDeps.native / Compile / packageBin / mappings).value, Compile / packageSrc / mappings ++= (airspecDeps.native / Compile / packageSrc / mappings).value, libraryDependencies ++= Seq( - // "org.scala-sbt" % "test-interface" % "1.0", "org.scala-native" %%% "test-interface" % "0.5.1" - //("org.portable-scala" %%% "portable-scala-reflect" % "1.1.2").cross(CrossVersion.for3Use2_13) ) ) // This should be Optional dependency, but using Provided dependency for bloop which doesn't support Optional. From 7f01c458f012caedd4684bd33f8851084bbe41b5 Mon Sep 17 00:00:00 2001 From: "Taro L. Saito" Date: Sun, 21 Apr 2024 00:56:37 -0700 Subject: [PATCH 11/16] Add airspec Scala 3 + Scala Native CI --- .github/workflows/test.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8a81811a03..ce37f80f68 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -224,6 +224,9 @@ jobs: - name: Scala JVM and Scala.js Test run: ../sbt "++airspecJVM/test; ++airspecJS/test" working-directory: ./airspec + - name: Scala Native Test + run: ../sbt "++ 3; airspecNative/test" + working-directory: ./airspec - name: Publish Test Report uses: mikepenz/action-junit-report@v4 if: always() # always run even if the previous step fails From 54237f45ff53806ac89d1e39f2e77525737b5d2f Mon Sep 17 00:00:00 2001 From: "Taro L. Saito" Date: Sun, 21 Apr 2024 01:00:09 -0700 Subject: [PATCH 12/16] Fix tests --- airspec/src/test/scala/examples/RxTest.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/airspec/src/test/scala/examples/RxTest.scala b/airspec/src/test/scala/examples/RxTest.scala index 5d5b187b0b..2803df9652 100644 --- a/airspec/src/test/scala/examples/RxTest.scala +++ b/airspec/src/test/scala/examples/RxTest.scala @@ -28,7 +28,9 @@ class RxTest extends AirSpec { } test("return Rx") { - skip("Skip Rx timer test for Scala Native") + if (isScalaNative) { + skip("Skip Rx timer test for Scala Native") + } Rx.intervalMillis(10).map(_ => v.set(true)) } From 01442abb3165f1ee70d496d57eef166569e74b07 Mon Sep 17 00:00:00 2001 From: "Taro L. Saito" Date: Sun, 21 Apr 2024 01:17:34 -0700 Subject: [PATCH 13/16] Fix nullary method call for Scala Native compatibility --- .../scala-3/java/util/logging/Logger.scala | 6 ++--- .../src/main/scala/wvlet/log/LogFormat.scala | 24 +++++++++---------- .../src/main/scala/wvlet/log/LogRecord.scala | 6 ++--- .../src/main/scala/wvlet/log/Logger.scala | 6 ++--- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/airframe-log/.native/src/main/scala-3/java/util/logging/Logger.scala b/airframe-log/.native/src/main/scala-3/java/util/logging/Logger.scala index e62b82ecf0..5aac70e365 100644 --- a/airframe-log/.native/src/main/scala-3/java/util/logging/Logger.scala +++ b/airframe-log/.native/src/main/scala-3/java/util/logging/Logger.scala @@ -22,7 +22,7 @@ class Logger(parent: Option[Logger], name: String) { } def log(record: LogRecord): Unit = { - if(isLoggable(record.level)) { + if(isLoggable(record.getLevel())) { if(record.getLoggerName() == null) { record.setLoggerName(name) } @@ -101,7 +101,7 @@ abstract class Formatter: def format(record: LogRecord): String -case class LogRecord(level: Level, msg: String) extends Serializable: +class LogRecord(_level: Level, msg: String) extends Serializable: private val millis = System.currentTimeMillis() private var loggerName = "" private var thrown: Throwable = null @@ -109,7 +109,7 @@ case class LogRecord(level: Level, msg: String) extends Serializable: def getMessage(): String = msg def getMillis(): Long = millis def getLoggerName(): String = loggerName - def getLevel(): Level = level + def getLevel(): Level = _level def getThrown(): Throwable = thrown def setLoggerName(name: String): Unit = { diff --git a/airframe-log/src/main/scala/wvlet/log/LogFormat.scala b/airframe-log/src/main/scala/wvlet/log/LogFormat.scala index 067b3cb940..ff021a6e6c 100644 --- a/airframe-log/src/main/scala/wvlet/log/LogFormat.scala +++ b/airframe-log/src/main/scala/wvlet/log/LogFormat.scala @@ -105,11 +105,11 @@ object LogFormatter extends AnsiColorPalette { object TSVLogFormatter extends LogFormatter { override def formatLog(record: LogRecord): String = { val s = Seq.newBuilder[String] - s += formatTimestampWithNoSpaace(record.getMillis) + s += formatTimestampWithNoSpaace(record.getMillis()) s += record.level.toString s += currentThreadName s += record.leafLoggerName - s += record.getMessage + s += record.getMessage() val log = s.result().mkString("\t") record.cause match { @@ -128,7 +128,7 @@ object LogFormatter extends AnsiColorPalette { object SimpleLogFormatter extends LogFormatter { override def formatLog(r: LogRecord): String = { val log = - s"[${highlightLog(r.level, r.leafLoggerName)}] ${highlightLog(r.level, r.getMessage)}" + s"[${highlightLog(r.level, r.leafLoggerName)}] ${highlightLog(r.level, r.getMessage())}" appendStackTrace(log, r) } } @@ -140,7 +140,7 @@ object LogFormatter extends AnsiColorPalette { override def formatLog(r: LogRecord): String = { val logTag = highlightLog(r.level, r.level.name) val log = - f"${withColor(Console.BLUE, formatTimestamp(r.getMillis))} ${logTag}%14s [${withColor(Console.WHITE, r.leafLoggerName)}] ${highlightLog(r.level, r.getMessage)}" + f"${withColor(Console.BLUE, formatTimestamp(r.getMillis()))} ${logTag}%14s [${withColor(Console.WHITE, r.leafLoggerName)}] ${highlightLog(r.level, r.getMessage())}" appendStackTrace(log, r) } } @@ -157,10 +157,10 @@ object LogFormatter extends AnsiColorPalette { val logTag = highlightLog(r.level, r.level.name) val log = - f"${withColor(Console.BLUE, formatTimestamp(r.getMillis))} ${logTag}%14s [${withColor( + f"${withColor(Console.BLUE, formatTimestamp(r.getMillis()))} ${logTag}%14s [${withColor( Console.WHITE, r.leafLoggerName - )}] ${highlightLog(r.level, r.getMessage)} ${loc}" + )}] ${highlightLog(r.level, r.getMessage())} ${loc}" appendStackTrace(log, r) } } @@ -174,10 +174,10 @@ object LogFormatter extends AnsiColorPalette { val logTag = highlightLog(r.level, r.level.name) val log = - f"${withColor(Console.BLUE, formatTimestamp(r.getMillis))} [${withColor(BRIGHT_BLUE, currentThreadName)}] ${logTag}%14s [${withColor( + f"${withColor(Console.BLUE, formatTimestamp(r.getMillis()))} [${withColor(BRIGHT_BLUE, currentThreadName)}] ${logTag}%14s [${withColor( Console.WHITE, r.leafLoggerName - )}] ${highlightLog(r.level, r.getMessage)} ${loc}" + )}] ${highlightLog(r.level, r.getMessage())} ${loc}" appendStackTrace(log, r) } } @@ -193,7 +193,7 @@ object LogFormatter extends AnsiColorPalette { .getOrElse("") val log = - f"${formatTimestamp(r.getMillis)} ${r.level.name}%5s [${r.leafLoggerName}] ${r.getMessage} ${loc}" + f"${formatTimestamp(r.getMillis())} ${r.level.name}%5s [${r.leafLoggerName}] ${r.getMessage()} ${loc}" appendStackTrace(log, r, coloring = false) } } @@ -205,11 +205,11 @@ object LogFormatter extends AnsiColorPalette { override def formatLog(r: LogRecord): String = { val loc = r.source - .map(source => s" ${withColor(Console.BLUE, s"- ${r.getLoggerName}(${source.fileLoc})")}") + .map(source => s" ${withColor(Console.BLUE, s"- ${r.getLoggerName()}(${source.fileLoc})")}") .getOrElse("") val log = - s"[${highlightLog(r.level, r.level.name)}] ${highlightLog(r.level, r.getMessage)}$loc" + s"[${highlightLog(r.level, r.level.name)}] ${highlightLog(r.level, r.getMessage())}$loc" appendStackTrace(log, r) } } @@ -219,7 +219,7 @@ object LogFormatter extends AnsiColorPalette { */ object BareFormatter extends LogFormatter { override def formatLog(r: LogRecord): String = { - val m = r.getMessage + val m = r.getMessage() r.cause match { case Some(ex) => s"${m}\n${formatStacktrace(ex)}" diff --git a/airframe-log/src/main/scala/wvlet/log/LogRecord.scala b/airframe-log/src/main/scala/wvlet/log/LogRecord.scala index b54b5c983e..181970ae9f 100644 --- a/airframe-log/src/main/scala/wvlet/log/LogRecord.scala +++ b/airframe-log/src/main/scala/wvlet/log/LogRecord.scala @@ -17,8 +17,8 @@ import java.util.{logging => jl} object LogRecord { def apply(record: jl.LogRecord): LogRecord = { - val l = LogRecord(LogLevel(record.getLevel), None, record.getMessage, Option(record.getThrown)) - l.setLoggerName(record.getLoggerName) + val l = LogRecord(LogLevel(record.getLevel()), None, record.getMessage(), Option(record.getThrown())) + l.setLoggerName(record.getLoggerName()) l } @@ -40,7 +40,7 @@ case class LogRecord(level: LogLevel, source: Option[LogSource], message: String cause.foreach(setThrown(_)) def leafLoggerName: String = { - val name = getLoggerName + val name = getLoggerName() leafLoggerNameCache.getOrElseUpdate( name, { name match { diff --git a/airframe-log/src/main/scala/wvlet/log/Logger.scala b/airframe-log/src/main/scala/wvlet/log/Logger.scala index 7ce4141045..93f5d77dab 100644 --- a/airframe-log/src/main/scala/wvlet/log/Logger.scala +++ b/airframe-log/src/main/scala/wvlet/log/Logger.scala @@ -51,11 +51,11 @@ class Logger( if (l == null) { LogLevel.INFO } else { - val jlLevel = l.getLevel + val jlLevel = l.getLevel() if (jlLevel != null) { LogLevel(jlLevel) } else { - getLogLevelOf(l.getParent) + getLogLevelOf(l.getParent()) } } } @@ -77,7 +77,7 @@ class Logger( } def getParent: Option[Logger] = { - Option(wrapped.getParent).map(x => Logger(x.getName)) + Option(wrapped.getParent()).map(x => Logger(x.getName())) } def addHandler(h: jl.Handler): Unit = { From ae5d770ce2ecad050837d77bf1a2dc9217d6ec83 Mon Sep 17 00:00:00 2001 From: "Taro L. Saito" Date: Sun, 21 Apr 2024 01:24:40 -0700 Subject: [PATCH 14/16] Add airspec for Scala Native + Scala 3 publish steps --- .github/workflows/release-airspec.yml | 1 + airspec/build.sbt | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release-airspec.yml b/.github/workflows/release-airspec.yml index 5a9613f00c..aeaed4610e 100644 --- a/.github/workflows/release-airspec.yml +++ b/.github/workflows/release-airspec.yml @@ -29,6 +29,7 @@ jobs: PGP_PASSPHRASE: ${{ secrets.PGP_PASSPHRASE }} run: | ../sbt "+airspecJVM/publishSigned; +airspecJS/publishSigned" + ../sbt "++ 3; airspecNative/publishSigned" working-directory: ./airspec - name: Release to Sonatype env: diff --git a/airspec/build.sbt b/airspec/build.sbt index 1ccea48b37..6594eb014c 100644 --- a/airspec/build.sbt +++ b/airspec/build.sbt @@ -1,13 +1,13 @@ // A short cut for publishing snapshots to Sonatype addCommandAlias( "publishSnapshots", - s"+airspecJVM/publish; +airspecJS/publish" + s"+airspecJVM/publish; +airspecJS/publish; ++ 3; airspecNative/publish" ) // [Development purpose] publish all artifacts to the local repo addCommandAlias( "publishAllLocal", - s"+airspecJVM/publishLocal; +airspecJS/publishLocal;" + s"+airspecJVM/publishLocal; +airspecJS/publishLocal; ++ 3; airspecNative/publishLocal" ) // Reload build.sbt on changes From 6daaaf7357c61270f7dbe5e6508d7156649d214b Mon Sep 17 00:00:00 2001 From: "Taro L. Saito" Date: Sun, 21 Apr 2024 01:27:58 -0700 Subject: [PATCH 15/16] Fix settings --- airspec/build.sbt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/airspec/build.sbt b/airspec/build.sbt index 6594eb014c..ef08c7a1f4 100644 --- a/airspec/build.sbt +++ b/airspec/build.sbt @@ -335,6 +335,7 @@ lazy val airspec = pomPostProcess := excludePomDependency(Seq("airspec-deps", "airspec_2.12", "airspec_2.13")) ) .jvmSettings( + airspecJVMBuildSettings, // Embed dependent project codes to make airspec a single jar Compile / packageBin / mappings ++= (airspecDeps.jvm / Compile / packageBin / mappings).value, Compile / packageSrc / mappings ++= (airspecDeps.jvm / Compile / packageSrc / mappings).value, @@ -353,6 +354,7 @@ lazy val airspec = } ) .jsSettings( + airspecJSBuildSettings, Compile / packageBin / mappings ++= (airspecDeps.js / Compile / packageBin / mappings).value .filter(x => x._2 != "JS_DEPENDENCIES"), Compile / packageSrc / mappings ++= (airspecDeps.js / Compile / packageSrc / mappings).value, @@ -364,6 +366,7 @@ lazy val airspec = ) ) .nativeSettings( + airspecNativeBuildSettings, // Embed dependent project codes to make airspec a single jar Compile / packageBin / mappings ++= (airspecDeps.native / Compile / packageBin / mappings).value, Compile / packageSrc / mappings ++= (airspecDeps.native / Compile / packageSrc / mappings).value, From 24bc6d33a3e12dc4c4da62c1385259362e442610 Mon Sep 17 00:00:00 2001 From: "Taro L. Saito" Date: Sun, 21 Apr 2024 01:30:21 -0700 Subject: [PATCH 16/16] Fix cross-publish settings --- .github/workflows/release-airspec.yml | 3 +-- airspec/build.sbt | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release-airspec.yml b/.github/workflows/release-airspec.yml index aeaed4610e..2cd2c49923 100644 --- a/.github/workflows/release-airspec.yml +++ b/.github/workflows/release-airspec.yml @@ -28,8 +28,7 @@ jobs: env: PGP_PASSPHRASE: ${{ secrets.PGP_PASSPHRASE }} run: | - ../sbt "+airspecJVM/publishSigned; +airspecJS/publishSigned" - ../sbt "++ 3; airspecNative/publishSigned" + ../sbt "+airspecJVM/publishSigned; +airspecJS/publishSigned; +airspecNative/publishSigned" working-directory: ./airspec - name: Release to Sonatype env: diff --git a/airspec/build.sbt b/airspec/build.sbt index ef08c7a1f4..633263d2ad 100644 --- a/airspec/build.sbt +++ b/airspec/build.sbt @@ -1,13 +1,13 @@ // A short cut for publishing snapshots to Sonatype addCommandAlias( "publishSnapshots", - s"+airspecJVM/publish; +airspecJS/publish; ++ 3; airspecNative/publish" + s"+airspecJVM/publish; +airspecJS/publish; +airspecNative/publish" ) // [Development purpose] publish all artifacts to the local repo addCommandAlias( "publishAllLocal", - s"+airspecJVM/publishLocal; +airspecJS/publishLocal; ++ 3; airspecNative/publishLocal" + s"+airspecJVM/publishLocal; +airspecJS/publishLocal; +airspecNative/publishLocal" ) // Reload build.sbt on changes