Skip to content

Commit 200bc65

Browse files
committed
Merge pull request #158 from lustefaniak/scala-js-support
Add support for cross compile to Scala.js
2 parents f649e50 + dd36d9c commit 200bc65

File tree

15 files changed

+494
-21
lines changed

15 files changed

+494
-21
lines changed

project/Scoverage.scala

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,17 @@ import sbt._
33
import sbtrelease.ReleasePlugin
44
import sbtrelease.ReleasePlugin.ReleaseKeys
55
import com.typesafe.sbt.pgp.PgpKeys
6+
import org.scalajs.sbtplugin.cross.CrossProject
7+
import org.scalajs.sbtplugin.cross.CrossType
8+
import org.scalajs.sbtplugin.ScalaJSPlugin
9+
import org.scalajs.sbtplugin.ScalaJSPlugin.autoImport._
610

711
object Scoverage extends Build {
812

913
val Org = "org.scoverage"
1014
val Scala = "2.11.7"
1115
val MockitoVersion = "1.9.5"
12-
val ScalatestVersion = "2.2.2"
16+
val ScalatestVersion = "3.0.0-M15"
1317

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

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

75-
lazy val runtime = Project("scalac-scoverage-runtime", file("scalac-scoverage-runtime"))
76+
lazy val runtime = CrossProject("scalac-scoverage-runtime", file("scalac-scoverage-runtime"), CrossType.Full)
7677
.settings(name := "scalac-scoverage-runtime")
7778
.settings(appSettings: _*)
79+
.jvmSettings(
80+
libraryDependencies ++= Seq(
81+
"org.mockito" % "mockito-all" % MockitoVersion % "test",
82+
"org.scalatest" %% "scalatest" % ScalatestVersion % "test"
83+
),
84+
javaOptions += "-XX:MaxMetaspaceSize=2048m"
85+
)
86+
.jsSettings(
87+
libraryDependencies += "org.scalatest" %%% "scalatest" % ScalatestVersion,
88+
scalaJSStage := FastOptStage
89+
)
90+
91+
lazy val `scalac-scoverage-runtimeJVM` = runtime.jvm
92+
lazy val `scalac-scoverage-runtimeJS` = runtime.js
7893

7994
lazy val plugin = Project("scalac-scoverage-plugin", file("scalac-scoverage-plugin"))
80-
.dependsOn(runtime % "test")
95+
.dependsOn(`scalac-scoverage-runtimeJVM` % "test")
8196
.settings(name := "scalac-scoverage-plugin")
8297
.settings(appSettings: _*)
98+
.settings(javaOptions += "-XX:MaxMetaspaceSize=2048m")
8399
.settings(libraryDependencies ++= Seq(
100+
"org.mockito" % "mockito-all" % MockitoVersion % "test",
101+
"org.scalatest" %% "scalatest" % ScalatestVersion % "test",
84102
"org.scala-lang" % "scala-reflect" % scalaVersion.value % "provided",
85103
"org.scala-lang" % "scala-compiler" % scalaVersion.value % "provided",
86104
"org.joda" % "joda-convert" % "1.6" % "test",
@@ -96,4 +114,4 @@ object Scoverage extends Build {
96114
Nil
97115
}
98116
})
99-
}
117+
}

project/plugins.sbt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,5 @@ addSbtPlugin("org.scalastyle" %% "scalastyle-sbt-plugin" % "0.3.2")
55
addSbtPlugin("com.typesafe.sbt" % "sbt-pgp" % "0.8.3")
66

77
addSbtPlugin("com.github.gseitz" % "sbt-release" % "0.8.5")
8+
9+
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.9")

scalac-scoverage-plugin/src/test/scala/scoverage/ScoverageCompiler.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ object ScoverageCompiler {
5151
dir
5252
}
5353

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

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

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package scalajssupport
2+
3+
import scala.scalajs.js
4+
import js.Dynamic.{ global => g }
5+
6+
/**
7+
* This wraps RhinoFile, NodeFile, or PhantomFile depending on which javascript
8+
* environment is being used, and emulates a subset of the java.io.File API.
9+
*/
10+
class File(path: String) {
11+
import File._
12+
13+
val _file = jsFile(path)
14+
15+
def this(path: String, child: String) = {
16+
this(File.pathJoin(path, child))
17+
}
18+
19+
def delete(): Unit = {
20+
_file.delete()
21+
}
22+
def getAbsolutePath(): String = {
23+
_file.getAbsolutePath()
24+
}
25+
26+
def getName(): String = {
27+
_file.getName()
28+
}
29+
30+
def getPath(): String = {
31+
_file.getPath()
32+
}
33+
34+
def isDirectory(): Boolean = {
35+
_file.isDirectory()
36+
}
37+
38+
def mkdirs(): Unit = {
39+
_file.mkdirs()
40+
}
41+
42+
def listFiles(): Array[File] = {
43+
_file.listFiles().toArray
44+
}
45+
46+
def listFiles(filter: FileFilter): Array[File] = {
47+
_file.listFiles().filter(filter.accept).toArray
48+
}
49+
50+
def readFile(): String = {
51+
_file.readFile()
52+
}
53+
54+
override def toString: String = {
55+
getPath()
56+
}
57+
}
58+
59+
object File {
60+
val jsFile: JsFileObject = if (js.Dynamic.global.hasOwnProperty("Packages").asInstanceOf[Boolean])
61+
RhinoFile
62+
else if (!js.Dynamic.global.hasOwnProperty("window").asInstanceOf[Boolean])
63+
NodeFile
64+
else
65+
PhantomFile
66+
// Factorize this
67+
68+
def pathJoin(path: String, child: String): String =
69+
jsFile.pathJoin(path, child)
70+
71+
def write(path: String, data: String, mode: String = "a") =
72+
jsFile.write(path, data, mode)
73+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package scalajssupport
2+
3+
/**
4+
* Emulates a subset of the java.io.FileWriter API required for scoverage to work.
5+
*/
6+
class FileWriter(file: File, append: Boolean) {
7+
def this(file: File) = this(file, false)
8+
def this(file: String) = this(new File(file), false)
9+
def this(file: String, append: Boolean) = this(new File(file), append)
10+
11+
def append(csq: CharSequence) = {
12+
File.write(file.getPath, csq.toString)
13+
this
14+
}
15+
16+
def close(): Unit = {
17+
// do nothing as we don't open a FD to the file, as phantomJS does not use FDs
18+
}
19+
20+
override def finalize(): Unit = close()
21+
22+
def flush() = {}
23+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package scalajssupport
2+
3+
trait JsFile {
4+
def delete(): Unit
5+
def getAbsolutePath(): String
6+
7+
def getName(): String
8+
9+
def getPath(): String
10+
11+
def isDirectory(): Boolean
12+
13+
def mkdirs(): Unit
14+
15+
def listFiles(): Array[File]
16+
17+
def listFiles(filter: FileFilter): Array[File] = {
18+
listFiles().filter(filter.accept)
19+
}
20+
21+
def readFile(): String
22+
}
23+
24+
trait FileFilter {
25+
def accept(file: File): Boolean
26+
}
27+
28+
trait JsFileObject {
29+
def write(path: String, data: String, mode: String = "a")
30+
def pathJoin(path: String, child: String): String
31+
def apply(path: String): JsFile
32+
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
package scalajssupport
2+
3+
import scala.scalajs.js
4+
5+
class NodeFile(path: String) extends JsFile {
6+
def this(path: String, child: String) = {
7+
this(NodeFile.nodePath.join(path, child))
8+
}
9+
10+
def delete(): Unit = {
11+
if (isDirectory()) NodeFile.fs.rmdirSync(path)
12+
else NodeFile.fs.unlinkSync(path)
13+
}
14+
15+
def getAbsolutePath(): String = {
16+
NodeFile.fs.realpathSync(path)
17+
}
18+
19+
def getName(): String = {
20+
NodeFile.nodePath.basename(path)
21+
}
22+
23+
def getPath(): String = {
24+
path
25+
}
26+
27+
def isDirectory(): Boolean = {
28+
try {
29+
NodeFile.fs.lstatSync(path).isDirectory()
30+
} catch {
31+
// return false if the file does not exist
32+
case e: Exception => false
33+
}
34+
}
35+
36+
def mkdirs(): Unit = {
37+
path.split("/").foldLeft("")((acc: String, x: String) => {
38+
val new_acc = NodeFile.nodePath.join(acc, x)
39+
try {
40+
NodeFile.fs.mkdirSync(new_acc)
41+
} catch {
42+
case e: Exception =>
43+
}
44+
new_acc
45+
})
46+
}
47+
48+
def listFiles(): Array[File] = {
49+
val files = NodeFile.fs.readdirSync(path)
50+
val filesArray = new Array[File](files.length)
51+
for ((item, i) <- filesArray.zipWithIndex) {
52+
filesArray(i) = new File(NodeFile.nodePath.join(this.getPath(), files(i)))
53+
}
54+
filesArray
55+
}
56+
57+
def readFile(): String = {
58+
NodeFile.fs.readFileSync(path, js.Dynamic.literal(encoding = "utf-8"))
59+
}
60+
61+
}
62+
63+
@js.native
64+
trait FSStats extends js.Object {
65+
def isDirectory(): Boolean = js.native
66+
}
67+
68+
@js.native
69+
trait FS extends js.Object {
70+
def closeSync(fd: Int): Unit = js.native
71+
def lstatSync(path: String): FSStats = js.native
72+
def mkdirSync(path: String): Unit = js.native
73+
def openSync(path: String, flags: String): Int = js.native
74+
def realpathSync(path: String): String = js.native
75+
def readdirSync(path: String): js.Array[String] = js.native
76+
def readFileSync(path: String, options: js.Dynamic): String = js.native
77+
def rmdirSync(path: String): Unit = js.native
78+
def unlinkSync(path: String): Unit = js.native
79+
def writeFileSync(path: String, data: String, options: js.Dynamic = js.Dynamic.literal()): Unit = js.native
80+
}
81+
82+
@js.native
83+
trait NodePath extends js.Object {
84+
def basename(path: String): String = js.native
85+
def join(paths: String*): String = js.native
86+
}
87+
88+
private[scalajssupport] object NodeFile extends JsFileObject {
89+
val fs: FS = js.Dynamic.global.require("fs").asInstanceOf[FS]
90+
val nodePath: NodePath = js.Dynamic.global.require("path").asInstanceOf[NodePath]
91+
def write(path: String, data: String, mode: String = "a") = {
92+
fs.writeFileSync(path, data, js.Dynamic.literal(flag = mode))
93+
}
94+
95+
def pathJoin(path: String, child: String) = {
96+
nodePath.join(path, child)
97+
}
98+
99+
def apply(path: String) = {
100+
new NodeFile(path)
101+
}
102+
}

0 commit comments

Comments
 (0)