Skip to content

Commit

Permalink
Updates for Scala 3.5
Browse files Browse the repository at this point in the history
  • Loading branch information
propensive committed Jun 5, 2024
1 parent d3924d8 commit 74c6ec9
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 53 deletions.
41 changes: 21 additions & 20 deletions src/core/guillotine.scala
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ trait Executor[ResultType]:

trait ProcessRef:
def pid: Pid
def kill()(using GenericLogger): Unit
def abort()(using GenericLogger): Unit
def kill(): Unit binds GenericLogger
def abort(): Unit binds GenericLogger
def alive: Boolean
def attend(): Unit
def startTime[InstantType: SpecificInstant]: Optional[InstantType]
Expand All @@ -95,8 +95,8 @@ object OsProcess:

class OsProcess private (java: ProcessHandle) extends ProcessRef:
def pid: Pid = Pid(java.pid)
def kill()(using GenericLogger): Unit = java.destroy()
def abort()(using GenericLogger): Unit = java.destroyForcibly()
def kill(): Unit binds GenericLogger = java.destroy()
def abort(): Unit binds GenericLogger = java.destroyForcibly()
def alive: Boolean = java.isAlive
def attend(): Unit = java.onExit.nn.get()

Expand Down Expand Up @@ -147,12 +147,12 @@ class Process[+ExecType <: Label, ResultType](process: java.lang.Process) extend
case 0 => ExitStatus.Ok
case other => ExitStatus.Fail(other)

def abort()(using logger: GenericLogger): Unit =
logger.info(t"The process with PID ${pid.value} was aborted")
def abort(): Unit binds GenericLogger =
bond[GenericLogger].info(t"The process with PID ${pid.value} was aborted")
process.destroy()

def kill()(using logger: GenericLogger): Unit =
logger.warn(t"The process with PID ${pid.value} was killed")
def kill(): Unit binds GenericLogger =
bond[GenericLogger].warn(t"The process with PID ${pid.value} was killed")
process.destroyForcibly()

def osProcess(using Errant[PidError]) = OsProcess(pid)
Expand All @@ -172,18 +172,18 @@ class Process[+ExecType <: Label, ResultType](process: java.lang.Process) extend
sealed trait Executable:
type Exec <: Label

def fork[ResultType]()(using working: WorkingDirectory, logger: GenericLogger)
: Process[Exec, ResultType] raises ExecError
def fork[ResultType]()(using working: WorkingDirectory)
: Process[Exec, ResultType] binds GenericLogger raises ExecError

def exec[ResultType]()
(using working: WorkingDirectory, logger: GenericLogger, executor: Executor[ResultType])
: ResultType raises ExecError =
(using working: WorkingDirectory, executor: Executor[ResultType])
: ResultType binds GenericLogger raises ExecError =

fork[ResultType]().await()

def apply[ResultType]()(using erased commandOutput: CommandOutput[Exec, ResultType])
(using working: WorkingDirectory, logger: GenericLogger, executor: Executor[ResultType])
: ResultType raises ExecError =
(using working: WorkingDirectory, executor: Executor[ResultType])
: ResultType binds GenericLogger raises ExecError =

fork[ResultType]().await()

Expand Down Expand Up @@ -221,8 +221,8 @@ object Command:
given Show[Command] = command => formattedArguments(command.arguments)

case class Command(arguments: Text*) extends Executable:
def fork[ResultType]()(using working: WorkingDirectory, logger: GenericLogger)
: Process[Exec, ResultType] raises ExecError =
def fork[ResultType]()(using working: WorkingDirectory)
: Process[Exec, ResultType] binds GenericLogger raises ExecError =

val processBuilder = ProcessBuilder(arguments.ss*)
processBuilder.directory(ji.File(working.directory().s))
Expand All @@ -240,8 +240,8 @@ object Pipeline:
given Show[Pipeline] = _.commands.map(_.show).join(t" | ")

case class Pipeline(commands: Command*) extends Executable:
def fork[ResultType]()(using working: WorkingDirectory, logger: GenericLogger)
: Process[Exec, ResultType] raises ExecError =
def fork[ResultType]()(using working: WorkingDirectory)
: Process[Exec, ResultType] binds GenericLogger raises ExecError =

val processBuilders = commands.map: command =>
val processBuilder = ProcessBuilder(command.arguments.ss*)
Expand All @@ -250,7 +250,7 @@ case class Pipeline(commands: Command*) extends Executable:

processBuilder.nn

logger.info(t"Starting pipelined processes ${this}")
bond[GenericLogger].info(t"Starting pipelined processes ${this}")

val pipeline = ProcessBuilder.startPipeline(processBuilders.asJava).nn.asScala.to(List).last
new Process[Exec, ResultType](pipeline)
Expand Down Expand Up @@ -374,7 +374,6 @@ trait Parameterizable:
def show(value: Self): Text

object Guillotine:
given Realm = realm"guillotine"

def sh(context: Expr[StringContext], parts: Expr[Seq[Any]])(using Quotes): Expr[Command] =
import quotes.reflect.*
Expand All @@ -385,3 +384,5 @@ object Guillotine:
(Refinement(TypeRepr.of[Command], "Exec", bounds).asType: @unchecked) match
case '[type commandType <: Command; commandType] =>
'{${Sh.Prefix.expand(context, parts)}.asInstanceOf[commandType]}

given Realm = realm"guillotine"
5 changes: 4 additions & 1 deletion src/core/posix.scala
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,9 @@ trait PosixCommandOutputs:
erased given uuencode: CommandOutput["uuencode", Text] = ###
erased given waitCommand: CommandOutput["wait", Text] = ###
erased given wc: CommandOutput["wc", Text] = ###
erased given which[PathType](using erased SpecificPath { type Self = PathType }): CommandOutput["which", PathType] = ###

erased given which[PathType](using erased PathType is SpecificPath)
: CommandOutput["which", PathType] = ###

erased given who: CommandOutput["who", Text] = ###
erased given write: CommandOutput["write", Text] = ###
64 changes: 32 additions & 32 deletions src/test/tests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,110 +31,110 @@ import contingency.*, errorHandlers.throwUnsafely

import unsafeExceptions.canThrowAny

given Log[Text] = logging.silent
given SimpleLogger = logging.silent

object Tests extends Suite(t"Guillotine tests"):
def run(): Unit =
suite(t"Parsing tests"):
test(t"parse simple command"):
sh"ls -la"
.assert(_ == Command(t"ls", t"-la"))

test(t"parse a substitution"):
val flags = t"-la"
val file = t"filename"
sh"ls $flags"
.assert(_ == Command(t"ls", t"-la"))

test(t"parse two substitutions"):
val flags = t"-la"
val file = t"filename"
sh"ls $flags $file"
.assert(_ == Command(t"ls", t"-la", t"filename"))

test(t"parse irregular spacing"):
val flags = t"-la"
val file = t"filename"
sh"ls $flags $file"
.assert(_ == Command(t"ls", t"-la", t"filename"))

test(t"parse irregular spacing 2"):
val flags = t"-la"
val file = t"filename"
sh"ls $flags $file"
.assert(_ == Command(t"ls", t"-la", t"filename"))

test(t"adjacent substitutions"):
val a = t"a"
val b = t"b"
sh"ls $a$b"
.assert(_ == Command(t"ls", t"ab"))

test(t"substitute a list"):
val a = List(t"a", t"b")
sh"ls $a"
.assert(_ == Command(t"ls", t"a", t"b"))

test(t"substitute a single-quoted list"):
val a = List(t"a", t"b")
sh"ls '$a'"
.assert(_ == Command(t"ls", t"a b"))

test(t"substitute in a double-quoted list"):
val a = List(t"a", t"b")
sh"""ls "$a""""
.assert(_ == Command(t"ls", t"a b"))

test(t"insertion after arg"):
val a = List(t"a", t"b")
sh"""ls ${a}x"""
.assert(_ == Command(t"ls", t"a", t"bx"))

test(t"insertion before arg"):
val a = List(t"a", t"b")
sh"""ls x${a}"""
.assert(_ == Command(t"ls", t"xa", t"b"))

test(t"insertion before quoted arg"):
val a = List(t"a", t"b")
sh"""ls ${a}'x'"""
.assert(_ == Command(t"ls", t"a", t"bx"))

test(t"insertion after quoted arg"):
val a = List(t"a", t"b")
sh"""ls 'x'${a}"""
.assert(_ == Command(t"ls", t"xa", t"b"))

test(t"empty list insertion"):
val a = List()
sh"""ls ${a}"""
.assert(_ == Command(t"ls"))

test(t"empty list insertion"):
val a = List()
sh"""ls '${a}'"""
.assert(_ == Command(t"ls", t""))

test(t"empty parameters"):
sh"""ls '' ''"""
.assert(_ == Command(t"ls", t"", t""))

test(t"one empty parameter, specified twice"):
sh"""ls ''''"""
.assert(_ == Command(t"ls", t""))

test(t"single quote inside double quotes"):
sh"""ls "'" """
.assert(_ == Command(t"ls", t"'"))

test(t"double quote inside single quotes"):
sh"""ls '"' """
.assert(_ == Command(t"ls", t"\""))

test(t"escaped double quote"):
sh"""ls \" """
.assert(_ == Command(t"ls", t"\""))

test(t"escaped single quote"):
sh"""ls \' """
.assert(_ == Command(t"ls", t"'"))
Expand All @@ -143,11 +143,12 @@ object Tests extends Suite(t"Guillotine tests"):
test(t"simple command"):
sh"echo Hello World".debug
.check(_ == t"""sh"echo Hello World"""")


println(sh"echo 'Hello World'".debug)
test(t"simple command with space"):
sh"echo 'Hello World'".debug
.check(_ == t"""sh"echo 'Hello World'"""")

test(t"simple command with quote and space"):
Command(t"echo", t"Don't stop").debug
.check(_ == t"sh\"\"\"echo \"Don't stop\"\"\"\"")
Expand All @@ -164,7 +165,7 @@ object Tests extends Suite(t"Guillotine tests"):
test(t"check that two commands written differently are equivalent"):
sh"echo 'hello world'"
.assert(_ == sh"""echo "hello world"""")

test(t"check that two commands written with different whitespace are equivalent"):
sh"one two three"
.assert(_ == sh"one two three")
Expand Down Expand Up @@ -199,27 +200,27 @@ object Tests extends Suite(t"Guillotine tests"):
sh"sleep 0.2".fork[Unit]()
System.currentTimeMillis - t0
.assert(_ <= 100L)

test(t"exec sleeping process"):
val t0 = System.currentTimeMillis
sh"sleep 0.2".exec[Unit]()
System.currentTimeMillis - t0
.assert(_ >= 200L)

test(t"fork and await sleeping process"):
val t0 = System.currentTimeMillis
val proc = sh"sleep 0.2".fork[Unit]()
proc.await()
System.currentTimeMillis - t0
.assert(_ >= 200L)

test(t"fork and abort sleeping process"):
val t0 = System.currentTimeMillis
val proc = sh"sleep 0.2".fork[Unit]()
proc.abort()
System.currentTimeMillis - t0
.assert(_ <= 100L)

test(t"fork and kill sleeping process"):
val t0 = System.currentTimeMillis
val proc = sh"sleep 0.2".fork[Unit]()
Expand All @@ -230,7 +231,7 @@ object Tests extends Suite(t"Guillotine tests"):
test(t"successful exit status"):
sh"echo hello".exec[ExitStatus]()
.assert(_ == ExitStatus.Ok)

test(t"failed exit status"):
sh"false".exec[ExitStatus]()
.assert(_ == ExitStatus.Fail(1))
Expand All @@ -243,9 +244,8 @@ object Tests extends Suite(t"Guillotine tests"):
test(t"implied return type"):
sh"echo 'Hello world'"()
.assert(_ == t"Hello world")

test(t"implied return type for `which`"):
import filesystemInterfaces.galileiApi
import filesystemApi.galileiPath
sh"which cat"()
.assert(_ == Unix / p"bin" / p"cat")

0 comments on commit 74c6ec9

Please sign in to comment.