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

Scala Native support #397

Merged
merged 6 commits into from
Jan 29, 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
10 changes: 7 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,9 @@ jobs:
strategy:
fail-fast: false
matrix:
java: ['[email protected]']
scala: ['2.11.12', '2.12.17', '2.13.8', '3.2.2']
java: ['17']
scala: ['2.12.17', '2.13.8', '3.3.0']
platform: ['JVM', 'Native']
steps:
- name: Checkout current branch
uses: actions/[email protected]
Expand All @@ -64,8 +65,11 @@ jobs:
java-version: ${{ matrix.java }}
- name: Cache scala dependencies
uses: coursier/cache-action@v6
- name: Install libuv
if: matrix.platform == 'Native'
run: sudo apt-get update && sudo apt-get install -y libuv1-dev
- name: Run tests
run: sbt ++${{ matrix.scala }} zioProcess/test
run: sbt ++${{ matrix.scala }} zioProcess${{ matrix.platform }}/test

ci:
runs-on: ubuntu-20.04
Expand Down
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,12 @@ Key features of the ZIO Process:
In order to use this library, we need to add the following line in our `build.sbt` file:

```scala
libraryDependencies += "dev.zio" %% "zio-process" % "0.7.1"
libraryDependencies += "dev.zio" %% "zio-process" % "0.7.2"
```

## Native support
Some features might have a different behaviour when using Scala Native. Creating non-existent commands do not throw a corresponding error. `bash` command might be needed when executing a script. In some cases, using `ZStreams` as standard input might block the process. Instead, a Java `InputStream` can be used to write to the standard input of the process.

## Example

Here is a simple example of using ZIO Process:
Expand Down
42 changes: 30 additions & 12 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import BuildHelper._
import sbtwelcome._
import sbt.addSbtPlugin
//import sbtcrossproject.CrossPlugin.autoImport._

inThisBuild(
List(
Expand Down Expand Up @@ -44,30 +46,47 @@ usefulTasks := Seq(
UsefulTask("", "testOnly *.YourSpec -- -t \"YourLabel\"", "Only runs tests with matching term")
)

val zioVersion = "2.0.9"
val zioVersion = "2.0.21"

lazy val root =
project
.in(file("."))
.settings(publish / skip := true)
.aggregate(zioProcess, docs)
.settings(
publish / skip := true,
crossScalaVersions := Nil
)
.aggregate(zioProcess.jvm, zioProcess.native, docs)

lazy val zioProcess =
project
crossProject(JVMPlatform, NativePlatform)
.in(file("zio-process"))
.settings(stdSettings("zio-process"))
.settings(crossProjectSettings)
.settings(buildInfoSettings("zio.process"))
.settings(
testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework")),
.jvmSettings(testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework")))
.jvmSettings(
libraryDependencies ++= Seq(
"dev.zio" %% "zio" % zioVersion,
"dev.zio" %% "zio-streams" % zioVersion,
"org.scala-lang.modules" %% "scala-collection-compat" % "2.9.0",
"dev.zio" %% "zio-test" % zioVersion % "test",
"dev.zio" %% "zio-test-sbt" % zioVersion % "test"
"dev.zio" %% "zio-test" % zioVersion % Test,
"dev.zio" %% "zio-test-sbt" % zioVersion % Test
)
)
.enablePlugins(BuildInfoPlugin)
.jvmSettings(dottySettings)
.nativeSettings(Test / fork := false)
.nativeSettings(testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework")))
.nativeSettings(
libraryDependencies ++= Seq(
"dev.zio" %%% "zio" % zioVersion,
"dev.zio" %%% "zio-streams" % zioVersion,
"org.scala-lang.modules" %%% "scala-collection-compat" % "2.9.0",
"dev.zio" %%% "zio-test" % zioVersion % Test,
"dev.zio" %%% "zio-test-sbt" % zioVersion % Test,
"io.github.cquiroz" %%% "scala-java-time" % "2.5.0" % Test
)
)

lazy val docs = project
.in(file("zio-process-docs"))
Expand All @@ -76,13 +95,12 @@ lazy val docs = project
moduleName := "zio-process-docs",
scalacOptions -= "-Yno-imports",
scalacOptions -= "-Xfatal-warnings",
crossScalaVersions -= Scala211,
libraryDependencies ++= Seq("dev.zio" %% "zio" % zioVersion),
projectName := "ZIO Process",
mainModuleName := (zioProcess / moduleName).value,
mainModuleName := (zioProcess.jvm / moduleName).value,
projectStage := ProjectStage.ProductionReady,
ScalaUnidoc / unidoc / unidocProjectFilter := inProjects(zioProcess),
ScalaUnidoc / unidoc / unidocProjectFilter := inProjects(zioProcess.jvm),
docsPublishBranch := "series/2.x"
)
.dependsOn(zioProcess)
.dependsOn(zioProcess.jvm)
.enablePlugins(WebsitePlugin)
3 changes: 3 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ In order to use this library, we need to add the following line in our `build.sb
libraryDependencies += "dev.zio" %% "zio-process" % "@VERSION@"
```

## Native support
Some features might have a different behaviour when using Scala Native. Creating non-existent commands do not throw a corresponding error. `bash` command might be needed when executing a script. In some cases, using `ZStreams` as standard input might block the process. Instead, a Java `InputStream` can be used to write to the standard input of the process.

## Example

Here is a simple example of using ZIO Process:
Expand Down
80 changes: 78 additions & 2 deletions project/BuildHelper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import sbt.Keys._
import sbt._
import sbtbuildinfo.BuildInfoKeys._
import sbtbuildinfo._
import sbtcrossproject.CrossPlugin.autoImport._

object BuildHelper {
private val versions: Map[String, String] = {
Expand All @@ -18,7 +19,6 @@ object BuildHelper {
}.toMap
}

val Scala211: String = versions("2.11")
val Scala212: String = versions("2.12")
val Scala213: String = versions("2.13")
val Scala3: String = versions("3")
Expand Down Expand Up @@ -93,9 +93,85 @@ object BuildHelper {
def stdSettings(prjName: String) = Seq(
name := s"$prjName",
fork := true,
crossScalaVersions := Seq(Scala211, Scala212, Scala213, Scala3),
crossScalaVersions := Seq(Scala212, Scala213),
ThisBuild / scalaVersion := Scala213,
scalacOptions := stdOptions ++ extraOptions(scalaVersion.value),
incOptions ~= (_.withLogRecompileOnMacro(false))
)

def platformSpecificSources(platform: String, conf: String, baseDirectory: File)(versions: String*) =
for {
platform <- List("shared", platform)
version <- "scala" :: versions.toList.map("scala-" + _)
result = baseDirectory.getParentFile / platform.toLowerCase / "src" / conf / version
if result.exists
} yield result

def crossPlatformSources(scalaVer: String, platform: String, conf: String, baseDir: File) = {
val versions = CrossVersion.partialVersion(scalaVer) match {
case Some((2, 11)) =>
List("2.11", "2.11+", "2.11-2.12", "2.x")
case Some((2, 12)) =>
List("2.12", "2.11+", "2.12+", "2.11-2.12", "2.12-2.13", "2.x")
case Some((2, 13)) =>
List("2.13", "2.11+", "2.12+", "2.13+", "2.12-2.13", "2.x")
case Some((3, 0)) =>
List("dotty", "2.11+", "2.12+", "2.13+", "3.x")
case _ =>
List()
}
platformSpecificSources(platform, conf, baseDir)(versions: _*)
}

lazy val crossProjectSettings = Seq(
Compile / unmanagedSourceDirectories ++= {
crossPlatformSources(
scalaVersion.value,
crossProjectPlatform.value.identifier,
"main",
baseDirectory.value
)
},
Test / unmanagedSourceDirectories ++= {
crossPlatformSources(
scalaVersion.value,
crossProjectPlatform.value.identifier,
"test",
baseDirectory.value
)
}
)

val dottySettings = Seq(
crossScalaVersions += Scala3,
scalacOptions ++= {
if (scalaVersion.value == Scala3)
Seq("-noindent")
else
Seq()
},
scalacOptions --= {
if (scalaVersion.value == Scala3)
Seq("-Xfatal-warnings")
else
Seq()
},
Compile / doc / sources := {
val old = (Compile / doc / sources).value
if (scalaVersion.value == Scala3) {
Nil
} else {
old
}
},
Test / parallelExecution := {
val old = (Test / parallelExecution).value
if (scalaVersion.value == Scala3) {
false
} else {
old
}
}
)

}
8 changes: 5 additions & 3 deletions project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.0")

addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.4.4")
addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.4.5")

addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.11.0")

addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.0.7")

addSbtPlugin("org.scalameta" % "sbt-mdoc" % "2.3.7")

addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "1.5.6")
addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "1.5.9")

addSbtPlugin("com.github.sbt" % "sbt-unidoc" % "0.5.0")

addSbtPlugin("com.github.sbt" % "sbt-ci-release" % "1.5.11")

addSbtPlugin("com.github.reibitto" % "sbt-welcome" % "0.2.2")

addSbtPlugin("dev.zio" % "zio-sbt-website" % "0.3.4")
addSbtPlugin("dev.zio" % "zio-sbt-website" % "0.3.4")
addSbtPlugin("org.portable-scala" % "sbt-scala-native-crossproject" % "1.3.2")
addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.4.17")

libraryDependencies += "org.snakeyaml" % "snakeyaml-engine" % "2.6"

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright 2017-2020 John A. De Goes and the ZIO Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package zio.process

import scala.annotation.nowarn
import java.io.File
import zio.NonEmptyChunk

private[process] trait CommandPlatformSpecific {

@nowarn
protected def checkDirectory(dir: File): Boolean = true

protected def adaptCommand(command: NonEmptyChunk[String]): NonEmptyChunk[String] = command

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,20 @@ package zio.process
import zio.stream.ZStream
import zio.{ Chunk, Queue }

import java.io.{ ByteArrayInputStream, File }
import java.io.ByteArrayInputStream
import java.nio.charset.{ Charset, StandardCharsets }
import java.io.File
import java.nio.file.Path
import java.io.InputStream

sealed trait ProcessInput

object ProcessInput {
final case class FromStream(stream: ZStream[Any, CommandError, Byte], flushChunksEagerly: Boolean)
extends ProcessInput

case object Inherit extends ProcessInput
case object Pipe extends ProcessInput

/**
* Returns a ProcessInput from an array of bytes.
*/
def fromByteArray(bytes: Array[Byte]): ProcessInput =
ProcessInput.FromStream(
ZStream.fromInputStream(new ByteArrayInputStream(bytes)).mapError(CommandError.IOError.apply),
flushChunksEagerly = false
)
final case class JavaStream(stream: InputStream, flushChunksEagerly: Boolean) extends ProcessInput
case object Inherit extends ProcessInput
case object Pipe extends ProcessInput

/**
* Returns a ProcessInput from a file.
Expand All @@ -58,6 +51,15 @@ object ProcessInput {
flushChunksEagerly = false
)

/**
* Returns a ProcessInput from an array of bytes.
*/
def fromByteArray(bytes: Array[Byte]): ProcessInput =
ProcessInput.FromStream(
ZStream.fromInputStream(new ByteArrayInputStream(bytes)).mapError(CommandError.IOError.apply),
flushChunksEagerly = false
)

/**
* Returns a ProcessInput from a queue of bytes to send to the process in a controlled manner.
*/
Expand Down Expand Up @@ -87,4 +89,5 @@ object ProcessInput {
ZStream.fromChunks(Chunk.fromArray(text.getBytes(StandardCharsets.UTF_8))),
flushChunksEagerly = false
)

}
Loading
Loading