Skip to content

Add support for cross compile to Scala.js #158

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

Merged
merged 5 commits into from
Jun 1, 2016
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
36 changes: 27 additions & 9 deletions project/Scoverage.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@ import sbt._
import sbtrelease.ReleasePlugin
import sbtrelease.ReleasePlugin.ReleaseKeys
import com.typesafe.sbt.pgp.PgpKeys
import org.scalajs.sbtplugin.cross.CrossProject
import org.scalajs.sbtplugin.cross.CrossType
import org.scalajs.sbtplugin.ScalaJSPlugin
import org.scalajs.sbtplugin.ScalaJSPlugin.autoImport._

object Scoverage extends Build {

val Org = "org.scoverage"
val Scala = "2.11.7"
val MockitoVersion = "1.9.5"
val ScalatestVersion = "2.2.2"
val ScalatestVersion = "3.0.0-M15"

lazy val LocalTest = config("local") extend Test

Expand All @@ -25,10 +29,6 @@ object Scoverage extends Build {
resolvers := ("releases" at "https://oss.sonatype.org/service/local/staging/deploy/maven2") +: resolvers.value,
concurrentRestrictions in Global += Tags.limit(Tags.Test, 1),
javacOptions := Seq("-source", "1.6", "-target", "1.6"),
libraryDependencies ++= Seq(
"org.mockito" % "mockito-all" % MockitoVersion % "test",
"org.scalatest" %% "scalatest" % ScalatestVersion % "test"
),
publishTo <<= version {
(v: String) =>
val nexus = "https://oss.sonatype.org/"
Expand Down Expand Up @@ -70,17 +70,35 @@ object Scoverage extends Build {
.settings(name := "scalac-scoverage")
.settings(appSettings: _*)
.settings(publishArtifact := false)
.aggregate(plugin, runtime)
.settings(javaOptions += "-XX:MaxMetaspaceSize=2048m")
.aggregate(plugin, runtime.jvm, runtime.js)

lazy val runtime = Project("scalac-scoverage-runtime", file("scalac-scoverage-runtime"))
lazy val runtime = CrossProject("scalac-scoverage-runtime", file("scalac-scoverage-runtime"), CrossType.Full)
.settings(name := "scalac-scoverage-runtime")
.settings(appSettings: _*)
.jvmSettings(
libraryDependencies ++= Seq(
"org.mockito" % "mockito-all" % MockitoVersion % "test",
"org.scalatest" %% "scalatest" % ScalatestVersion % "test"
),
javaOptions += "-XX:MaxMetaspaceSize=2048m"
)
.jsSettings(
libraryDependencies += "org.scalatest" %%% "scalatest" % ScalatestVersion,
scalaJSStage := FastOptStage
)

lazy val `scalac-scoverage-runtimeJVM` = runtime.jvm
lazy val `scalac-scoverage-runtimeJS` = runtime.js

lazy val plugin = Project("scalac-scoverage-plugin", file("scalac-scoverage-plugin"))
.dependsOn(runtime % "test")
.dependsOn(`scalac-scoverage-runtimeJVM` % "test")
.settings(name := "scalac-scoverage-plugin")
.settings(appSettings: _*)
.settings(javaOptions += "-XX:MaxMetaspaceSize=2048m")
.settings(libraryDependencies ++= Seq(
"org.mockito" % "mockito-all" % MockitoVersion % "test",
"org.scalatest" %% "scalatest" % ScalatestVersion % "test",
"org.scala-lang" % "scala-reflect" % scalaVersion.value % "provided",
"org.scala-lang" % "scala-compiler" % scalaVersion.value % "provided",
"org.joda" % "joda-convert" % "1.6" % "test",
Expand All @@ -96,4 +114,4 @@ object Scoverage extends Build {
Nil
}
})
}
}
2 changes: 2 additions & 0 deletions project/plugins.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ addSbtPlugin("org.scalastyle" %% "scalastyle-sbt-plugin" % "0.3.2")
addSbtPlugin("com.typesafe.sbt" % "sbt-pgp" % "0.8.3")

addSbtPlugin("com.github.gseitz" % "sbt-release" % "0.8.5")

addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.9")
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ object ScoverageCompiler {
dir
}

private def runtimeClasses: File = new File("./scalac-scoverage-runtime/target/scala-2.11/classes")
private def runtimeClasses: File = new File("./scalac-scoverage-runtime/jvm/target/scala-2.11/classes")

private def findScalaJar(artifactId: String): File = findIvyJar("org.scala-lang", artifactId, ScalaVersion)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package scalajssupport

import scala.scalajs.js
import js.Dynamic.{ global => g }

/**
* This wraps RhinoFile, NodeFile, or PhantomFile depending on which javascript
* environment is being used, and emulates a subset of the java.io.File API.
*/
class File(path: String) {
import File._

val _file = jsFile(path)

def this(path: String, child: String) = {
this(File.pathJoin(path, child))
}

def delete(): Unit = {
_file.delete()
}
def getAbsolutePath(): String = {
_file.getAbsolutePath()
}

def getName(): String = {
_file.getName()
}

def getPath(): String = {
_file.getPath()
}

def isDirectory(): Boolean = {
_file.isDirectory()
}

def mkdirs(): Unit = {
_file.mkdirs()
}

def listFiles(): Array[File] = {
_file.listFiles().toArray
}

def listFiles(filter: FileFilter): Array[File] = {
_file.listFiles().filter(filter.accept).toArray
}

def readFile(): String = {
_file.readFile()
}

override def toString: String = {
getPath()
}
}

object File {
val jsFile: JsFileObject = if (js.Dynamic.global.hasOwnProperty("Packages").asInstanceOf[Boolean])
RhinoFile
else if (!js.Dynamic.global.hasOwnProperty("window").asInstanceOf[Boolean])
NodeFile
else
PhantomFile
// Factorize this

def pathJoin(path: String, child: String): String =
jsFile.pathJoin(path, child)

def write(path: String, data: String, mode: String = "a") =
jsFile.write(path, data, mode)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package scalajssupport

/**
* Emulates a subset of the java.io.FileWriter API required for scoverage to work.
*/
class FileWriter(file: File, append: Boolean) {
def this(file: File) = this(file, false)
def this(file: String) = this(new File(file), false)
def this(file: String, append: Boolean) = this(new File(file), append)

def append(csq: CharSequence) = {
File.write(file.getPath, csq.toString)
this
}

def close(): Unit = {
// do nothing as we don't open a FD to the file, as phantomJS does not use FDs
}

override def finalize(): Unit = close()

def flush() = {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package scalajssupport

trait JsFile {
def delete(): Unit
def getAbsolutePath(): String

def getName(): String

def getPath(): String

def isDirectory(): Boolean

def mkdirs(): Unit

def listFiles(): Array[File]

def listFiles(filter: FileFilter): Array[File] = {
listFiles().filter(filter.accept)
}

def readFile(): String
}

trait FileFilter {
def accept(file: File): Boolean
}

trait JsFileObject {
def write(path: String, data: String, mode: String = "a")
def pathJoin(path: String, child: String): String
def apply(path: String): JsFile
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package scalajssupport

import scala.scalajs.js

class NodeFile(path: String) extends JsFile {
def this(path: String, child: String) = {
this(NodeFile.nodePath.join(path, child))
}

def delete(): Unit = {
if (isDirectory()) NodeFile.fs.rmdirSync(path)
else NodeFile.fs.unlinkSync(path)
}

def getAbsolutePath(): String = {
NodeFile.fs.realpathSync(path)
}

def getName(): String = {
NodeFile.nodePath.basename(path)
}

def getPath(): String = {
path
}

def isDirectory(): Boolean = {
try {
NodeFile.fs.lstatSync(path).isDirectory()
} catch {
// return false if the file does not exist
case e: Exception => false
}
}

def mkdirs(): Unit = {
path.split("/").foldLeft("")((acc: String, x: String) => {
val new_acc = NodeFile.nodePath.join(acc, x)
try {
NodeFile.fs.mkdirSync(new_acc)
} catch {
case e: Exception =>
}
new_acc
})
}

def listFiles(): Array[File] = {
val files = NodeFile.fs.readdirSync(path)
val filesArray = new Array[File](files.length)
for ((item, i) <- filesArray.zipWithIndex) {
filesArray(i) = new File(NodeFile.nodePath.join(this.getPath(), files(i)))
}
filesArray
}

def readFile(): String = {
NodeFile.fs.readFileSync(path, js.Dynamic.literal(encoding = "utf-8"))
}

}

@js.native
trait FSStats extends js.Object {
def isDirectory(): Boolean = js.native
}

@js.native
trait FS extends js.Object {
def closeSync(fd: Int): Unit = js.native
def lstatSync(path: String): FSStats = js.native
def mkdirSync(path: String): Unit = js.native
def openSync(path: String, flags: String): Int = js.native
def realpathSync(path: String): String = js.native
def readdirSync(path: String): js.Array[String] = js.native
def readFileSync(path: String, options: js.Dynamic): String = js.native
def rmdirSync(path: String): Unit = js.native
def unlinkSync(path: String): Unit = js.native
def writeFileSync(path: String, data: String, options: js.Dynamic = js.Dynamic.literal()): Unit = js.native
}

@js.native
trait NodePath extends js.Object {
def basename(path: String): String = js.native
def join(paths: String*): String = js.native
}

private[scalajssupport] object NodeFile extends JsFileObject {
val fs: FS = js.Dynamic.global.require("fs").asInstanceOf[FS]
val nodePath: NodePath = js.Dynamic.global.require("path").asInstanceOf[NodePath]
def write(path: String, data: String, mode: String = "a") = {
fs.writeFileSync(path, data, js.Dynamic.literal(flag = mode))
}

def pathJoin(path: String, child: String) = {
nodePath.join(path, child)
}

def apply(path: String) = {
new NodeFile(path)
}
}
Loading