Skip to content

Commit

Permalink
Remove the IO capability (#220)
Browse files Browse the repository at this point in the history
  • Loading branch information
adamw authored Sep 23, 2024
1 parent fcd0979 commit 959f23f
Show file tree
Hide file tree
Showing 29 changed files with 131 additions and 623 deletions.
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,8 @@ project/plugins/project/
.idea*
.bsp
.metals
.vscode
.vscode
.bloop
metals.sbt

/notes.md
59 changes: 2 additions & 57 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,10 @@ compileDocumentation := {
(documentation / mdoc).toTask(" --out target/ox-doc").value
}

val useRequireIOPlugin =
// Based on:
// https://stackoverflow.com/questions/54660122/how-to-include-a-scala-compiler-plugin-from-a-local-path
Compile / scalacOptions ++= {
val jar = (plugin / Compile / Keys.`package`).value
System.setProperty("sbt.paths.plugin.jar", jar.getAbsolutePath)

val addPlugin = "-Xplugin:" + jar.getAbsolutePath
val dummy = "-Jdummy=" + jar.lastModified
Seq(addPlugin, dummy)
}

lazy val rootProject = (project in file("."))
.settings(commonSettings)
.settings(publishArtifact := false, name := "ox")
.aggregate(core, plugin, pluginTest, examples, kafka, mdcLogback)
.aggregate(core, examples, kafka, mdcLogback)

lazy val core: Project = (project in file("core"))
.settings(commonSettings)
Expand All @@ -49,48 +37,6 @@ lazy val core: Project = (project in file("core"))
"com.softwaremill.jox" % "channels" % "0.3.1",
scalaTest
),
// Check IO usage in core
useRequireIOPlugin,
Test / fork := true
)

lazy val plugin: Project = (project in file("plugin"))
.settings(commonSettings)
.settings(
name := "plugin",
libraryDependencies ++= Seq("org.scala-lang" %% "scala3-compiler" % scalaVersion.value, scalaTest)
)

lazy val pluginTest: Project = (project in file("plugin-test"))
.settings(commonSettings)
.settings(
name := "plugin-test",
libraryDependencies ++= Seq(
"org.scala-lang" %% "scala3-compiler" % scalaVersion.value,
scalaTest
),
publishArtifact := false,
// Playground testing
useRequireIOPlugin,
// Unit testing, based on:
// https://github.com/xebia-functional/munit-compiler-toolkit/
Test / javaOptions += {
val dependencyJars = (Compile / dependencyClasspath).value.files
val thisJar = (Compile / Keys.`package`).value
val `scala-compiler-classpath` =
(dependencyJars :+ thisJar)
.map(_.toPath.toAbsolutePath.toString())
.mkString(":")
s"-Dscala-compiler-classpath=${`scala-compiler-classpath`}"
},
Test / javaOptions += Def.taskDyn {
Def.task {
val _ = (plugin / Compile / Keys.`package`).value
val `scala-compiler-options` =
s"${(plugin / Compile / packageBin).value}"
s"""-Dscala-compiler-plugin=${`scala-compiler-options`}"""
}
}.value,
Test / fork := true
)

Expand Down Expand Up @@ -118,8 +64,7 @@ lazy val kafka: Project = (project in file("kafka"))
"org.apache.pekko" %% "pekko-connectors-kafka" % "1.0.0" % Test,
"org.apache.pekko" %% "pekko-stream" % "1.1.1" % Test,
scalaTest
),
useRequireIOPlugin
)
)
.dependsOn(core)

Expand Down
36 changes: 0 additions & 36 deletions core/src/main/scala/ox/IO.scala

This file was deleted.

22 changes: 10 additions & 12 deletions core/src/main/scala/ox/OxApp.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,8 @@ enum ExitCode(val code: Int):
*
* Certain aspects of exception handling can be configured using [[OxApp.Settings]] and overriding the `settings` method.
*
* The application's code is specified in a `run` method, which has two capabilities granted:
*
* - [[Ox]], to fork asynchronously computations, and register clean up of resources
* - [[IO]], to perform I/O operations
* The application's code is specified in a `run` method, which has the [[Ox]] capability granted: to fork asynchronously computations, and
* register clean up of resources
*/
trait OxApp:
protected def settings: OxApp.Settings = OxApp.Settings.Default
Expand All @@ -36,7 +34,7 @@ trait OxApp:
try
unsupervised {
val cancellableMainFork = forkCancellable {
try supervised(IO.unsafe(run(args.toVector)))
try supervised(run(args.toVector))
catch
case NonFatal(e) =>
settings.handleException(e)
Expand Down Expand Up @@ -67,7 +65,7 @@ trait OxApp:
try Runtime.getRuntime.addShutdownHook(thread)
catch case _: IllegalStateException => ()

def run(args: Vector[String])(using Ox, IO): ExitCode
def run(args: Vector[String])(using Ox): ExitCode
end OxApp

object OxApp:
Expand Down Expand Up @@ -107,11 +105,11 @@ object OxApp:

/** Simple variant of OxApp does not pass command line arguments and exits with exit code 0 if no exceptions were thrown. */
trait Simple extends OxApp:
override final def run(args: Vector[String])(using Ox, IO): ExitCode =
override final def run(args: Vector[String])(using Ox): ExitCode =
run
ExitCode.Success

def run(using Ox, IO): Unit
def run(using Ox): Unit

/** WithErrorMode variant of OxApp allows to specify what kind of error handling for the main function should be used. Base trait for
* integrations.
Expand All @@ -122,7 +120,7 @@ object OxApp:
* wrapper type for given ErrorMode
*/
trait WithErrorMode[E, F[_]](em: ErrorMode[E, F]) extends OxApp:
override final def run(args: Vector[String])(using Ox, IO): ExitCode =
override final def run(args: Vector[String])(using Ox): ExitCode =
val result = runWithErrors(args)
if em.isError(result) then handleError(em.getError(result))
else ExitCode.Success
Expand All @@ -133,7 +131,7 @@ object OxApp:
/** This template method is to be implemented by abstract classes that add integration for particular error handling data structure of
* type F[_].
*/
def runWithErrors(args: Vector[String])(using Ox, IO): F[ExitCode]
def runWithErrors(args: Vector[String])(using Ox): F[ExitCode]
end WithErrorMode

/** WithEitherErrors variant of OxApp integrates OxApp with an `either` block and allows for usage of `.ok()` combinators in the body of
Expand All @@ -145,8 +143,8 @@ object OxApp:
abstract class WithEitherErrors[E] extends WithErrorMode(EitherMode[E]()):
type EitherError[Err] = Label[Either[Err, ExitCode]]

override final def runWithErrors(args: Vector[String])(using Ox, IO): Either[E, ExitCode] =
override final def runWithErrors(args: Vector[String])(using Ox): Either[E, ExitCode] =
either[E, ExitCode](run(args))

def run(args: Vector[String])(using Ox, EitherError[E], IO): ExitCode
def run(args: Vector[String])(using Ox, EitherError[E]): ExitCode
end OxApp
4 changes: 2 additions & 2 deletions core/src/main/scala/ox/channels/SourceCompanionIOOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ trait SourceCompanionIOOps:
* @return
* a `Source` of chunks of bytes.
*/
def fromInputStream(is: InputStream, chunkSize: Int = 1024)(using Ox, StageCapacity, IO): Source[Chunk[Byte]] =
def fromInputStream(is: InputStream, chunkSize: Int = 1024)(using Ox, StageCapacity): Source[Chunk[Byte]] =
val chunks = StageCapacity.newChannel[Chunk[Byte]]
forkPropagate(chunks) {
try
Expand Down Expand Up @@ -54,7 +54,7 @@ trait SourceCompanionIOOps:
* @throws SecurityException
* If SecurityManager error occurs when opening the file.
*/
def fromFile(path: Path, chunkSize: Int = 1024)(using Ox, StageCapacity, IO): Source[Chunk[Byte]] =
def fromFile(path: Path, chunkSize: Int = 1024)(using Ox, StageCapacity): Source[Chunk[Byte]] =
if Files.isDirectory(path) then throw new IOException(s"Path $path is a directory")
val chunks = StageCapacity.newChannel[Chunk[Byte]]
val jFileChannel =
Expand Down
6 changes: 3 additions & 3 deletions core/src/main/scala/ox/channels/SourceIOOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ trait SourceIOOps[+T]:
* @throws IOException
* if an error occurs when writing or closing of the `OutputStream`.
*/
def toOutputStream(outputStream: OutputStream)(using T <:< Chunk[Byte], IO): Unit =
def toOutputStream(outputStream: OutputStream)(using T <:< Chunk[Byte]): Unit =
repeatWhile {
outer.receiveOrClosed() match
case ChannelClosed.Done =>
Expand All @@ -65,7 +65,7 @@ trait SourceIOOps[+T]:
* @throws IOException
* if an error occurs when opening the file or during the write process.
*/
def toFile(path: Path)(using T <:< Chunk[Byte], IO): Unit =
def toFile(path: Path)(using T <:< Chunk[Byte]): Unit =
if Files.isDirectory(path) then throw new IOException(s"Path $path is a directory")
val jFileChannel =
try {
Expand Down Expand Up @@ -93,7 +93,7 @@ trait SourceIOOps[+T]:
throw e
}

private inline def close(closeable: Closeable, cause: Option[Throwable] = None)(using IO): Unit =
private inline def close(closeable: Closeable, cause: Option[Throwable] = None): Unit =
try closeable.close()
catch
case NonFatal(closeException) =>
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/scala/ox/race.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import scala.annotation.tailrec
import scala.concurrent.TimeoutException
import scala.concurrent.duration.FiniteDuration
import scala.util.control.{ControlThrowable, NonFatal}
import scala.util.{Failure, Success, Try}
import scala.util.{Failure, Success}

/** A `Some` if the computation `t` took less than `duration`, and `None` otherwise. if the computation `t` throws an exception, it is
* propagated.
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/scala/ox/scheduling/scheduled.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package ox.scheduling
import ox.{EitherMode, ErrorMode, sleep}

import scala.annotation.tailrec
import scala.concurrent.duration.{Duration, FiniteDuration, DurationLong}
import scala.concurrent.duration.{FiniteDuration, DurationLong}
import scala.util.Try

/** The mode that specifies how to interpret the duration provided by the schedule. */
Expand Down
26 changes: 13 additions & 13 deletions core/src/test/scala/ox/OxAppTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class OxAppTest extends AnyFlatSpec with Matchers:
override def exit(exitCode: ExitCode): Unit =
ec = exitCode.code

override def run(args: Vector[String])(using Ox, IO): ExitCode = Success
override def run(args: Vector[String])(using Ox): ExitCode = Success

Main10.main(Array.empty)

Expand All @@ -43,7 +43,7 @@ class OxAppTest extends AnyFlatSpec with Matchers:
override private[ox] def exit(exitCode: ExitCode): Unit =
ec = exitCode.code

override def run(args: Vector[String])(using Ox, IO): ExitCode =
override def run(args: Vector[String])(using Ox): ExitCode =
forever: // will never finish
sleep(10.millis)

Expand All @@ -64,7 +64,7 @@ class OxAppTest extends AnyFlatSpec with Matchers:
var stackTrace = ""

object Main30 extends OxApp:
override def run(args: Vector[String])(using Ox, IO): ExitCode =
override def run(args: Vector[String])(using Ox): ExitCode =
Failure(23)

override private[ox] def exit(exitCode: ExitCode): Unit =
Expand All @@ -79,7 +79,7 @@ class OxAppTest extends AnyFlatSpec with Matchers:
// failure by throwing an exception

object Main31 extends OxApp:
override def run(args: Vector[String])(using Ox, IO): ExitCode =
override def run(args: Vector[String])(using Ox): ExitCode =
throw Exception("oh no")

override private[ox] def exit(exitCode: ExitCode): Unit =
Expand All @@ -100,7 +100,7 @@ class OxAppTest extends AnyFlatSpec with Matchers:
// failure by throwing an exception in a user fork

object Main32 extends OxApp:
override def run(args: Vector[String])(using Ox, IO): ExitCode =
override def run(args: Vector[String])(using Ox): ExitCode =
forkUser(throw Exception("oh no"))
Success

Expand Down Expand Up @@ -144,7 +144,7 @@ class OxAppTest extends AnyFlatSpec with Matchers:
OxApp.Settings.defaultHandleInterruptedException(t => handledExceptions = t :: handledExceptions)
)

override def run(args: Vector[String])(using Ox, IO): ExitCode =
override def run(args: Vector[String])(using Ox): ExitCode =
releaseAfterScope:
throw new Exception("bye!")

Expand All @@ -166,7 +166,7 @@ class OxAppTest extends AnyFlatSpec with Matchers:
override def exit(exitCode: ExitCode): Unit =
ec = exitCode.code

override def run(using Ox, IO): Unit = ()
override def run(using Ox): Unit = ()

Main50.main(Array.empty)

Expand All @@ -190,7 +190,7 @@ class OxAppTest extends AnyFlatSpec with Matchers:
override def exit(exitCode: ExitCode): Unit =
ec = exitCode.code

override def run(using Ox, IO): Unit =
override def run(using Ox): Unit =
forever:
sleep(10.millis)

Expand All @@ -207,7 +207,7 @@ class OxAppTest extends AnyFlatSpec with Matchers:
var stackTrace = ""

object Main70 extends OxApp.Simple:
override def run(using Ox, IO): Unit = throw Exception("oh no")
override def run(using Ox): Unit = throw Exception("oh no")

override private[ox] def exit(exitCode: ExitCode): Unit =
ec = exitCode.code
Expand Down Expand Up @@ -239,7 +239,7 @@ class OxAppTest extends AnyFlatSpec with Matchers:

override def handleError(e: FunException): ExitCode = Failure(e.code)

override def run(args: Vector[String])(using Ox, EitherError[FunException], IO): ExitCode =
override def run(args: Vector[String])(using Ox, EitherError[FunException]): ExitCode =
errOrEc.ok()

Main80.main(Array.empty)
Expand Down Expand Up @@ -267,7 +267,7 @@ class OxAppTest extends AnyFlatSpec with Matchers:
override private[ox] def exit(exitCode: ExitCode): Unit =
ec = exitCode.code

override def run(args: Vector[String])(using Ox, EitherError[FunException], IO): ExitCode =
override def run(args: Vector[String])(using Ox, EitherError[FunException]): ExitCode =
forever: // will never finish
sleep(10.millis)

Expand All @@ -287,7 +287,7 @@ class OxAppTest extends AnyFlatSpec with Matchers:
var stackTrace = ""

object Main100 extends OxApp.WithEitherErrors[FunException]:
override def run(args: Vector[String])(using Ox, EitherError[FunException], IO): ExitCode =
override def run(args: Vector[String])(using Ox, EitherError[FunException]): ExitCode =
errOrEc.ok()

override private[ox] def exit(exitCode: ExitCode): Unit =
Expand All @@ -302,7 +302,7 @@ class OxAppTest extends AnyFlatSpec with Matchers:
ec = Int.MinValue

object Main101 extends OxApp.WithEitherErrors[FunException]:
override def run(args: Vector[String])(using Ox, EitherError[FunException], IO): ExitCode =
override def run(args: Vector[String])(using Ox, EitherError[FunException]): ExitCode =
throw Exception("oh no")

override private[ox] def exit(exitCode: ExitCode): Unit =
Expand Down
Loading

0 comments on commit 959f23f

Please sign in to comment.