Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove the IO capability #220

Merged
merged 2 commits into from
Sep 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading