Skip to content

Commit

Permalink
Merge pull request #1155 from alexarchambault/develop
Browse files Browse the repository at this point in the history
Tweak new launcher
  • Loading branch information
alexarchambault authored Jun 14, 2023
2 parents 5f5d16c + 7ccede9 commit e5cdb6f
Show file tree
Hide file tree
Showing 9 changed files with 204 additions and 143 deletions.
1 change: 1 addition & 0 deletions build.sc
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ class Interpreter(val crossScalaVersion: String) extends AlmondModule {
)
def ivyDeps = Agg(
Deps.collectionCompat,
Deps.fansi,
Deps.scalatags.applyBinaryVersion213_3(scalaVersion()),
Deps.slf4jNop
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,47 +3,97 @@ package almond.cslogger
import almond.interpreter.api.OutputHandler
import almond.logger.LoggerContext

import java.lang.{Long => JLong}
import java.util.UUID
import java.util.concurrent.ConcurrentHashMap

import scala.collection.JavaConverters._

class NotebookCacheLogger(
publish: OutputHandler,
logCtx: LoggerContext
) extends coursierapi.CacheLogger {
private val log = logCtx(getClass)
import scalatags.Text.all._
var ids = new ConcurrentHashMap[String, String]
private var ids = new ConcurrentHashMap[String, String]
private var totalLength = new ConcurrentHashMap[String, JLong]
private var downloaded = new ConcurrentHashMap[String, JLong]
private var threadOpt = Option.empty[Thread]
private val updates = new ConcurrentHashMap[String, String]
private def newThread(): Thread =
new Thread("cs-logger") {
setDaemon(true)
def proceed(): Unit =
if (publish.canOutput()) {
val entries = updates.entrySet().asScala.toVector.map(e => (e.getKey, e.getValue))
for ((k, v) <- entries) {
publish.updateHtml(v, k)
updates.remove(k, v)
}
}
override def run(): Unit =
try
while (true) {
proceed()
Thread.sleep(25L)
}
catch {
case _: InterruptedException =>
proceed()
}
}
override def init(sizeHint: Integer): Unit = {
ids.clear()
updates.clear()
totalLength.clear()
downloaded.clear()
val t = newThread()
t.start()
threadOpt = Some(t)
}
override def stop(): Unit = {}
override def downloadingArtifact(url: String, artifact: coursierapi.Artifact): Unit = {
override def stop(): Unit =
for (t <- threadOpt) {
t.interrupt()
threadOpt = None
}
override def downloadingArtifact(url: String, artifact: coursierapi.Artifact): Unit =
if (publish.canOutput()) {
val newId = UUID.randomUUID().toString
val formerIdOpt = Option(ids.putIfAbsent(url, newId))
val id = formerIdOpt.getOrElse(newId)
val html = div("Downloading ", a(href := url, url))
publish.html(html.render, id)
}
override def downloadProgress(url: String, downloaded0: Long): Unit = {
downloaded.putIfAbsent(url, downloaded0: JLong)
val idOpt = Option(ids.get(url))
for (id <- idOpt; len <- Option(totalLength.get(url))) {
val pct = math.floor(100 * (downloaded0.toDouble / len)).toInt
val html = div("Downloading ", a(href := url, url), s" ($pct %)")
updates.put(id, html.render)
}
}
override def downloadProgress(url: String, downloaded: Long): Unit = {}
override def downloadedArtifact(url: String, success: Boolean): Unit = {
if (publish.canOutput()) {
val idOpt = Option(ids.get(url))
val msg = if (success) "Downloaded" else "Failed to download"
val html = div(s"$msg ", a(href := url, url))
idOpt match {
case Some(id) =>
publish.updateHtml(html.render, id)
case None =>
val idOpt = Option(ids.get(url))
idOpt match {
case Some(id) =>
val msg = if (success) "" else div("Failed to download ", a(href := url, url)).render
updates.put(id, msg)
case None =>
if (publish.canOutput()) {
val msg = if (success) "Downloaded" else "Failed to download"
val html = div(s"$msg ", a(href := url, url))
publish.html(html.render)
}
}
}
}
override def downloadLength(
url: String,
totalLength: Long,
totalLength0: Long,
alreadyDownloaded: Long,
watching: Boolean
): Unit = {}
): Unit = {
totalLength.put(url, totalLength0: JLong)
downloaded.putIfAbsent(url, alreadyDownloaded: JLong)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ package almond.launcher
import almond.channels.{Channel, Connection, Message => RawMessage}
import almond.channels.zeromq.ZeromqThreads
import almond.cslogger.NotebookCacheLogger
import almond.interpreter.ExecuteResult
import almond.interpreter.api.OutputHandler
import almond.kernel.install.Install
import almond.kernel.{Kernel, KernelThreads, MessageFile}
import almond.logger.{Level, LoggerContext}
import almond.protocol.RawJson
import almond.protocol.{Execute, RawJson}
import almond.util.ThreadUtil.singleThreadedExecutionContext
import caseapp.core.RemainingArgs
import caseapp.core.app.CaseApp
Expand Down Expand Up @@ -349,22 +350,42 @@ object Launcher extends CaseApp[LauncherOptions] {
new LauncherOutputHandler(firstMessage, conn)
}

val (actualKernelCommand0, scalaVersion, jvmOpt) = actualKernelCommand(
connectionFile,
leftoverMessagesFileOpt,
interpreter.lineCount,
options,
firstMessageIdOpt.toSeq,
interpreter.params,
outputHandlerOpt.getOrElse(OutputHandler.NopOutputHandler),
logCtx
)
val maybeActualKernelCommand =
try {
val (actualKernelCommand0, scalaVersion, jvmOpt) = actualKernelCommand(
connectionFile,
leftoverMessagesFileOpt,
interpreter.lineCount,
options,
firstMessageIdOpt.toSeq,
interpreter.params,
outputHandlerOpt.getOrElse(OutputHandler.NopOutputHandler),
logCtx
)

if (!options.quiet0)
for (outputHandler <- outputHandlerOpt) {
val toPrint =
s"Launching Scala $scalaVersion kernel" + jvmOpt.fold("")(jvm => s" with JVM $jvm")
outputHandler.stdout(toPrint + System.lineSeparator())
}

if (!options.quiet0)
for (outputHandler <- outputHandlerOpt) {
val toPrint =
s"Launching Scala $scalaVersion kernel" + jvmOpt.fold("")(jvm => s" with JVM $jvm")
outputHandler.stdout(toPrint + System.lineSeparator())
Right(actualKernelCommand0)
}
catch {
case NonFatal(e) if firstMessageOpt.nonEmpty =>
val firstMessage = firstMessageOpt.getOrElse(sys.error("Cannot happen"))
val err = ExecuteResult.Error.error(fansi.Color.Red, fansi.Color.Green, Some(e), "")
val errMsg = firstMessage.publish(
Execute.errorType,
Execute.Error("", "", List(err.message))
)
try conn.send(Channel.Publish, errMsg.asRawMessage).unsafeRunSync()(IORuntime.global)
catch {
case NonFatal(e) =>
throw new Exception(e)
}
Left(e)
}

for (outputHandler <- outputHandlerOpt)
Expand All @@ -382,6 +403,12 @@ object Launcher extends CaseApp[LauncherOptions] {
.unsafeRunSync()(IORuntime.global)
log.debug("ZeroMQ context closed")

launchActualKernel(actualKernelCommand0)
maybeActualKernelCommand match {
case Right(actualKernelCommand0) =>
val proc0 = os.proc(actualKernelCommand0.commandChunks, remainingArgs.unparsed)
launchActualKernel(proc0)
case Left(e) =>
throw new Exception(e)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -115,59 +115,8 @@ object LauncherInterpreter {

private val handlersMap = handlers.flatMap(h => h.keys.map(_ -> h)).toMap

// FIXME Also in almond.Execute
private def highlightFrame(
f: StackTraceElement,
highlightError: fansi.Attrs,
source: fansi.Attrs
) = {
val src =
if (f.isNativeMethod) source("Native Method")
else if (f.getFileName == null) source("Unknown Source")
else source(f.getFileName) ++ ":" ++ source(f.getLineNumber.toString)

val prefix :+ clsName = f.getClassName.split('.').toSeq
val prefixString = prefix.map(_ + '.').mkString("")
val clsNameString = clsName // .replace("$", error("$"))
val method =
fansi.Str(prefixString) ++ highlightError(clsNameString) ++ "." ++
highlightError(f.getMethodName)

fansi.Str(s" ") ++ method ++ "(" ++ src ++ ")"
}

// FIXME Also in almond.Execute
def showException(
ex: Throwable,
error: fansi.Attrs,
highlightError: fansi.Attrs,
source: fansi.Attrs
) = {

val cutoff = Set("$main", "evaluatorRunPrinter")
val traces = Ex.unapplySeq(ex).get.map(exception =>
error(exception.toString).render + System.lineSeparator() +
exception
.getStackTrace
.takeWhile(x => !cutoff(x.getMethodName))
.map(highlightFrame(_, highlightError, source))
.mkString(System.lineSeparator())
)
traces.mkString(System.lineSeparator())
}

// FIXME Also in almond.Execute
private def error(colors: Colors, exOpt: Option[Throwable], msg: String) =
ExecuteResult.Error(
msg + exOpt.fold("")(ex =>
(if (msg.isEmpty) "" else "\n") + showException(
ex,
colors.error,
fansi.Attr.Reset,
colors.literal
)
)
)
ExecuteResult.Error.error(colors.error, colors.literal, exOpt, msg)

// from Model.scala in Ammonite
object Ex {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ final case class LauncherOptions(
sharedDependencies: List[String] = Nil,
compileOnly: Option[Boolean] = None,
javaOpt: List[String] = Nil,
quiet: Option[Boolean] = None
quiet: Option[Boolean] = None,
silentImports: Option[Boolean] = None,
useNotebookCoursierLogger: Option[Boolean] = None
) {
// format: on

Expand All @@ -49,6 +51,10 @@ final case class LauncherOptions(
b ++= Seq("--predef", value)
for (value <- compileOnly)
b ++= Seq(s"--compile-only=$value")
for (value <- silentImports)
b ++= Seq(s"--silent-imports=$value")
for (value <- useNotebookCoursierLogger)
b ++= Seq(s"--use-notebook-coursier-logger=$value")
b.result()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,11 @@ final class Execute(
(
"Interrupted!" +: st
.takeWhile(x => !cutoff(x.getMethodName))
.map(Execute.highlightFrame(_, fansi.Attr.Reset, colors0().literal()))
.map(ExecuteResult.Error.highlightFrame(
_,
fansi.Attr.Reset,
colors0().literal()
))
).mkString(System.lineSeparator())
)
}
Expand All @@ -437,59 +441,6 @@ final class Execute(
}

object Execute {

// these come from Ammonite
// exception display was tweaked a bit (too much red for notebooks else)

private def highlightFrame(
f: StackTraceElement,
highlightError: fansi.Attrs,
source: fansi.Attrs
) = {
val src =
if (f.isNativeMethod) source("Native Method")
else if (f.getFileName == null) source("Unknown Source")
else source(f.getFileName) ++ ":" ++ source(f.getLineNumber.toString)

val prefix :+ clsName = f.getClassName.split('.').toSeq
val prefixString = prefix.map(_ + '.').mkString("")
val clsNameString = clsName // .replace("$", error("$"))
val method =
fansi.Str(prefixString) ++ highlightError(clsNameString) ++ "." ++
highlightError(f.getMethodName)

fansi.Str(s" ") ++ method ++ "(" ++ src ++ ")"
}

def showException(
ex: Throwable,
error: fansi.Attrs,
highlightError: fansi.Attrs,
source: fansi.Attrs
) = {

val cutoff = Set("$main", "evaluatorRunPrinter")
val traces = Ex.unapplySeq(ex).get.map(exception =>
error(exception.toString).render + System.lineSeparator() +
exception
.getStackTrace
.takeWhile(x => !cutoff(x.getMethodName))
.map(highlightFrame(_, highlightError, source))
.mkString(System.lineSeparator())
)
traces.mkString(System.lineSeparator())
}

private def error(colors: Colors, exOpt: Option[Throwable], msg: String) =
ExecuteResult.Error(
msg + exOpt.fold("")(ex =>
(if (msg.isEmpty) "" else "\n") + showException(
ex,
colors.error(),
fansi.Attr.Reset,
colors.literal()
)
)
)

def error(colors: Colors, exOpt: Option[Throwable], msg: String) =
ExecuteResult.Error.error(colors.error(), colors.literal(), exOpt, msg)
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package almond

import almond.api.JupyterApi
import almond.interpreter.ExecuteResult
import almond.interpreter.api.DisplayData
import ammonite.repl.api.{FrontEnd, ReplLoad}
import ammonite.repl.{FullReplAPI, SessionApiImpl}
Expand Down Expand Up @@ -137,7 +138,12 @@ final class ReplApiImpl(
.getOrElse(fansi.Color.LightGray)

val err =
Execute.showException(ex, colors0().error(), Attr.Reset, colors0().literal())
ExecuteResult.Error.showException(
ex,
colors0().error(),
Attr.Reset,
colors0().literal()
)
val s = messageColor("[last attempt failed]").render + "\n" + err
updatableResults.update(id, s, last = false)
case Right(value0) =>
Expand Down
Loading

0 comments on commit e5cdb6f

Please sign in to comment.