Skip to content

Commit

Permalink
Fixed ghost source files amongst other things
Browse files Browse the repository at this point in the history
  • Loading branch information
propensive committed Nov 18, 2022
1 parent 820828e commit 2ed4478
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 81 deletions.
5 changes: 3 additions & 2 deletions src/core/compilation.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import gossamer.*
import joviality.*
import tetromino.*
import escapade.*
import eucalyptus.*
import serpentine.*

import rendering.ansi
Expand All @@ -24,7 +25,7 @@ object Compiler:
def compile(id: Ref, pwd: Directory[Unix], files: List[File[Unix]], inputs: List[DiskPath[Unix]],
out: Directory[Unix], script: File[Unix], plugins: List[PluginRef], cancel: Promise[Unit],
owners: Map[DiskPath[Unix], Step])
(using Stdout, Monitor, Allocator, Environment)
(using Stdout, Monitor, Allocator, Environment, Log)
: Result =
import unsafeExceptions.canThrowAny
import dotty.tools.*, io.{File as _, *}, repl.*, dotc.core.*
Expand Down Expand Up @@ -84,7 +85,7 @@ object Compiler:

safely(Unix.parse(file)).option.map: p =>
val (root: DiskPath[Unix], step: Step) = owners.filter(_(0).precedes(p)).maxBy(_(0).parts.size)
val path = p.relativeTo(root)
val path = p.relativeTo(step.pwd.path)
CodeRange(step.id, path, pos.line, pos.startColumn, pos.endColumn, pos.endLine, content)

def getRanges(pos: dtdu.SourcePosition | Null, acc: List[CodeRange] = Nil): List[CodeRange] =
Expand Down
10 changes: 6 additions & 4 deletions src/core/irk.scala
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,10 @@ import rendering.ansi
erased given CanThrow[AppError] = compiletime.erasedValue
given LogFormat[File[Unix]] = LogFormat.standardAnsi
//given Log = logging.stdout(using monitors.global)

val LogFile = unsafely(Unix.parse(t"/var/log/irk.log").file(Ensure).sink)
given log: Log = Log(
{ case _ => unsafely(Unix.parse(t"/var/log/irk.log").file(Ensure).sink) }
{ case _ => LogFile }
)(using monitors.global)

object palette:
Expand Down Expand Up @@ -353,10 +355,10 @@ object Progress:
enum Update:
case Add(verb: Verb, hash: Digest[Crc32])
case Remove(verb: Verb, result: Result)
case Resize(cols: Int)
case Put(text: Text)
case Print
case SkipOne
case Sigwinch
case Stdout(verb: Verb, data: Bytes)

def titleText(title: Text): Text = t"\e]0;$title\u0007\b \b"
Expand All @@ -374,8 +376,8 @@ case class Progress(active: TreeMap[Verb, (Digest[Crc32], Long)],
)

def apply(update: Progress.Update)(using Stdout, Environment): Progress = update match
case Progress.Update.Sigwinch =>
this
case Progress.Update.Resize(cols) =>
copy(columns = cols)

case Progress.Update.Add(verb, hash) =>
add(verb, hash)
Expand Down
109 changes: 34 additions & 75 deletions src/core/main.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import rudiments.*
import turbulence.*
import acyclicity.*
import euphemism.*
import eucalyptus.Log
import joviality.*, filesystems.unix
import anticipation.*, integration.jovialityPath
import guillotine.*
Expand Down Expand Up @@ -50,6 +51,12 @@ object Irk extends Daemon():
case t"help" :: _ => Irk.help()
case t"init" :: name :: _ => Irk.init(unsafely(env.pwd.directory(Expect)), name)
case t"version" :: _ => Irk.showVersion()
case t"go" :: _ =>
unsafely:
Tty.capture:
Tty.stream[Keypress].take(10).foreach: event =>
eucalyptus.Log.info(t"Received keypress: ${event}")
ExitStatus.Ok
case t"build" :: params =>
val target = params.headOption.filter(!_.startsWith(t"-"))
val watch = params.contains(t"-w") || params.contains(t"--watch")
Expand Down Expand Up @@ -338,11 +345,15 @@ object Irk extends Daemon():
try
result.issues.groupBy(_.baseDir).to(List).map: (baseDir, issues) =>
issues.groupBy(_.code.path).to(List).map: (path, issues) =>
val file = unsafely(baseDir + path)
if !file.exists() then
Log.warn(t"Missing source file: ${file}")
unsafely(baseDir + path).file(Ensure) -> issues
.sortBy(_(0).modified)
.sortBy(_.last(0).modified).flatten

catch case err: IoError => throw AppError(ansi"a file containing an error was deleted: ${err.toString.show}", err)//: ${err.ansi}", err)
catch case err: IoError =>
throw AppError(ansi"a file containing an error was deleted: ${err.toString.show}", err)//: ${err.ansi}", err)

def arrow(k1: (Srgb, Text), k2: (Srgb, Text)): AnsiText =
def hc(c: Srgb): Srgb = if c.hsl.lightness > 0.5 then colors.Black else colors.White
Expand Down Expand Up @@ -475,18 +486,27 @@ object Irk extends Daemon():
Tty.capture:
val rootBuild = unsafely(env.pwd / t"build.irk")
val tap: Tap = Tap(true)

//Tty.reportSize()

def interrupts = Tty.stream[Keypress].collect:
case Keypress.Ctrl('C') => Event.Interrupt
case Keypress.Resize(width, _) => Event.Resize(width)
def interrupts = Tty.stream[Keypress].map:
case key =>
Log.fine(t"Got input: $key")
key
.collect:
case Keypress.Ctrl('C') =>
Log.fine(t"Received interrupt")
Event.Interrupt
case Keypress.Resize(width, _) =>
Log.fine(t"Received resize message")
Event.Resize(width)
.filter:
case Event.Interrupt =>
if !tap.state() then
summon[Monitor].cancel()
Log.fine(t"Ignored interrupt")
false
else true
else
Log.fine(t"Propagated interrupt")
true

case _ =>
true
Expand Down Expand Up @@ -540,7 +560,7 @@ object Irk extends Daemon():
running.foreach(_.abort())
if lastSuccess then ExitStatus.Ok else ExitStatus.Fail(1)
case Event.Resize(width) =>
loop(first, stream.tail, oldBuild, lastSuccess, browser, running, count, columns)
loop(first, stream.tail, oldBuild, lastSuccess, browser, running, count, width)
case Event.Changeset(fileChanges) =>
tap.pause()

Expand Down Expand Up @@ -588,6 +608,7 @@ object Irk extends Daemon():
Out.println(ansi"${colors.DodgerBlue}()")

val funnel: Funnel[Progress.Update] = Funnel()
funnel.put(Progress.Update.Resize(columns))
val totalTasks: Int = build.steps.size

val owners: Map[DiskPath[Unix], Step] = build.steps.flatMap: step =>
Expand Down Expand Up @@ -667,29 +688,25 @@ object Irk extends Daemon():
case Exec(browsers, url, start, stop) =>
val verb = Verb.Exec(ansi"main class ${palette.Class}($start)")

funnel.put(Progress.Update.Stdout(verb, t"Before main task\n".bytes))
val mainTask = Task(t"main"):
funnel.put(Progress.Update.Stdout(verb, t"Starting main task\n".bytes))
val hash = t"${build.hashes.get(step)}$start".digest[Crc32]
funnel.put(Progress.Update.Add(verb, hash))
running.foreach(_.abort())
val resources = step.allResources(build).map(_.path)
val classpath = (step.classpath(build) ++ resources).to(List)
funnel.put(Progress.Update.Stdout(verb, t"Launching JVM\n".bytes))
val jvm = Run.main(classpath)(start, stop)
val output = Task(t"stdout"):
jvm.stdout().foreach: data =>
funnel.put(Progress.Update.Stdout(verb, data))
funnel.put(Progress.Update.Stdout(verb, t"Running JVM with PID ${jvm.pid}\n".bytes))
val jvm = Run.main(irkJar(scriptFile).path :: classpath)(start, stop)
jvm


val subprocess: Jvm = mainTask.await()

val newResult: Result = subprocess.await() match
case ExitStatus.Ok =>
subprocess.stdout().foreach: data =>
funnel.put(Progress.Update.Stdout(verb, data))
result
case ExitStatus.Fail(n) =>
subprocess.stdout().foreach: data =>
funnel.put(Progress.Update.Stdout(verb, data))
Result.Terminal(ansi"Process returned exit status $n")

funnel.put(Progress.Update.Remove(verb, newResult))
Expand Down Expand Up @@ -750,8 +767,6 @@ object Irk extends Daemon():
case class ExecError(err: Exception)
extends Error(err"an exception was thrown while executing the task: ${err.getMessage.nn.show}")

case class TrapExitError(status: ExitStatus) extends Error(err"a call to System.exit was trapped: $status")

object Run:
import java.net.*

Expand All @@ -769,62 +784,6 @@ object Run:
: Jvm throws ClasspathRefError | IoError | StreamCutError | EnvError | NoValidJdkError =
jdk.launch(classpath, start, Nil)

def main2(classpath: List[DiskPath[Unix]])(start: Text, stop: Option[Text])(using Stdout): Subprocess =
val urls = classpath.map { path => URL(t"file://${path.fullname}/".s) }

def rootClassLoader(cl: ClassLoader): ClassLoader =
if cl.getParent == null then cl else rootClassLoader(cl.getParent.nn)

val parent = rootClassLoader(Thread.currentThread.nn.getContextClassLoader.nn)

val loader = new URLClassLoader(urls.to(Array)).nn

def invoke(className: Text): Any =
Run.synchronized:
if System.getSecurityManager != TrapExit then System.setSecurityManager(TrapExit)

val cls: Class[?] = loader.loadClass(className.s).nn
val method = cls.getMethods.nn.find(_.nn.getName == "main").get.nn
method.invoke(null, Array[String]())

val subprocess =
try
invoke(start)
Subprocess(None)
catch
case err: TrapExitError => Subprocess(Some(err.status))
case err: java.lang.reflect.InvocationTargetException => err.getCause match
case null => Subprocess(Some(ExitStatus(2)))
case err: TrapExitError => Subprocess(Some(err.status))
case err: Exception => Subprocess(Some(ExitStatus(1)))
case err: Throwable => Subprocess(Some(ExitStatus(2)))
case err: Exception => Subprocess(Some(ExitStatus(1)))
case err: Throwable => Subprocess(Some(ExitStatus(2)))

stop.map: stop =>
def term = try invoke(stop).unit catch case err: Exception => ()
val shutdownThread = Thread((() => term): Runnable)
Runtime.getRuntime.nn.addShutdownHook(shutdownThread)

subprocess.copy(terminate = Some({ () =>
Runtime.getRuntime.nn.removeShutdownHook(shutdownThread)
term
}))
.getOrElse(subprocess)

object TrapExit extends SecurityManager:
private var disabled: Boolean = false
override def checkPermission(perm: java.security.Permission): Unit = ()

override def checkExit(status: Int): Unit =
erased given CanThrow[TrapExitError] = compiletime.erasedValue
super.checkExit(status)
if !disabled then throw TrapExitError(ExitStatus(status))

def terminate(status: ExitStatus): Unit =
disabled = true
System.exit(status())

case class Subprocess(status: Option[ExitStatus], terminate: Option[() => Unit] = None):
def stop(): Unit = terminate.foreach(_())

Expand Down

0 comments on commit 2ed4478

Please sign in to comment.