Skip to content

Commit b93db05

Browse files
author
Semion Sidorenko
committed
Add support for scala.js
1 parent 5d0c924 commit b93db05

File tree

17 files changed

+653
-27
lines changed

17 files changed

+653
-27
lines changed

project/Scoverage.scala

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@ 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._
10+
//import org.scalajs.jsenv.phantomjs.PhantomJSEnv
11+
612

713
object Scoverage extends Build {
814

@@ -25,10 +31,7 @@ object Scoverage extends Build {
2531
resolvers := ("releases" at "https://oss.sonatype.org/service/local/staging/deploy/maven2") +: resolvers.value,
2632
concurrentRestrictions in Global += Tags.limit(Tags.Test, 1),
2733
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-
),
34+
javaOptions += "-XX:MaxMetaspaceSize=2048m",
3235
publishTo <<= version {
3336
(v: String) =>
3437
val nexus = "https://oss.sonatype.org/"
@@ -70,17 +73,30 @@ object Scoverage extends Build {
7073
.settings(name := "scalac-scoverage")
7174
.settings(appSettings: _*)
7275
.settings(publishArtifact := false)
73-
.aggregate(plugin, runtime)
76+
.aggregate(plugin, runtime.jvm, runtime.js)
7477

75-
lazy val runtime = Project("scalac-scoverage-runtime", file("scalac-scoverage-runtime"))
78+
lazy val runtime = CrossProject("scalac-scoverage-runtime", file("scalac-scoverage-runtime"), CrossType.Full)
7679
.settings(name := "scalac-scoverage-runtime")
7780
.settings(appSettings: _*)
81+
.jvmSettings(libraryDependencies ++= Seq(
82+
"org.mockito" % "mockito-all" % MockitoVersion % "test",
83+
"org.scalatest" %% "scalatest" % ScalatestVersion % "test"
84+
))
85+
.jsSettings(
86+
libraryDependencies += "com.lihaoyi" %%% "utest" % "0.3.0",
87+
testFrameworks += new TestFramework("utest.runner.Framework")
88+
)
89+
90+
lazy val `scalac-scoverage-runtimeJVM` = runtime.jvm
91+
lazy val `scalac-scoverage-runtimeJS` = runtime.js
7892

7993
lazy val plugin = Project("scalac-scoverage-plugin", file("scalac-scoverage-plugin"))
80-
.dependsOn(runtime % "test")
94+
.dependsOn(`scalac-scoverage-runtimeJVM` % "test")
8195
.settings(name := "scalac-scoverage-plugin")
8296
.settings(appSettings: _*)
8397
.settings(libraryDependencies ++= Seq(
98+
"org.mockito" % "mockito-all" % MockitoVersion % "test",
99+
"org.scalatest" %% "scalatest" % ScalatestVersion % "test",
84100
"org.scala-lang" % "scala-reflect" % scalaVersion.value % "provided",
85101
"org.scala-lang" % "scala-compiler" % scalaVersion.value % "provided",
86102
"org.joda" % "joda-convert" % "1.6" % "test",
@@ -96,4 +112,4 @@ object Scoverage extends Build {
96112
Nil
97113
}
98114
})
99-
}
115+
}

project/ScoveragePhantomJSEnv.scala

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
import org.scalajs.jsenv.phantomjs._
2+
import org.scalajs.jsenv._
3+
4+
import org.scalajs.core.tools.classpath._
5+
import org.scalajs.core.tools.io._
6+
import org.scalajs.core.tools.logging._
7+
8+
import org.scalajs.core.ir.Utils.{escapeJS, fixFileURI}
9+
10+
import java.io._
11+
12+
class ScoveragePhantomJSEnv (
13+
phantomjsPath: String = "phantomjs",
14+
addArgs: Seq[String] = Seq.empty,
15+
addEnv: Map[String, String] = Map.empty,
16+
override val autoExit: Boolean = true,
17+
jettyClassLoader: ClassLoader = null
18+
) extends PhantomJSEnv (phantomjsPath, addArgs, addEnv, autoExit, jettyClassLoader) {
19+
private[ScoveragePhantomJSEnv] trait WebsocketListener {
20+
def onRunning(): Unit
21+
def onOpen(): Unit
22+
def onClose(): Unit
23+
def onMessage(msg: String): Unit
24+
25+
def log(msg: String): Unit
26+
}
27+
override def jsRunner(classpath: CompleteClasspath, code: VirtualJSFile,
28+
logger: Logger, console: JSConsole): JSRunner = {
29+
new ScoveragePhantomRunner(classpath, code, logger, console)
30+
}
31+
32+
override def asyncRunner(classpath: CompleteClasspath, code: VirtualJSFile,
33+
logger: Logger, console: JSConsole): AsyncJSRunner = {
34+
new AsyncScoveragePhantomRunner(classpath, code, logger, console)
35+
}
36+
37+
override def comRunner(classpath: CompleteClasspath, code: VirtualJSFile,
38+
logger: Logger, console: JSConsole): ComJSRunner = {
39+
new ComScoveragePhantomRunner(classpath, code, logger, console)
40+
}
41+
42+
43+
protected class ScoveragePhantomRunner(classpath: CompleteClasspath,
44+
code: VirtualJSFile, logger: Logger, console: JSConsole
45+
) extends ExtRunner(classpath, code, logger, console)
46+
with AbstractScoveragePhantomRunner
47+
48+
protected class AsyncScoveragePhantomRunner(classpath: CompleteClasspath,
49+
code: VirtualJSFile, logger: Logger, console: JSConsole
50+
) extends AsyncExtRunner(classpath, code, logger, console)
51+
with AbstractScoveragePhantomRunner
52+
53+
protected class ComScoveragePhantomRunner(classpath: CompleteClasspath,
54+
code: VirtualJSFile, logger: Logger, console: JSConsole
55+
) extends ComPhantomRunner(classpath, code, logger, console)
56+
with ComJSRunner with AbstractScoveragePhantomRunner with WebsocketListener
57+
58+
protected trait AbstractScoveragePhantomRunner extends AbstractPhantomRunner {
59+
override protected def createTmpLauncherFile(): File = {
60+
val webF = createTmpWebpage()
61+
62+
val launcherTmpF = File.createTempFile("phantomjs-launcher", ".js")
63+
launcherTmpF.deleteOnExit()
64+
65+
val out = new FileWriter(launcherTmpF)
66+
67+
try {
68+
out.write(
69+
s"""// Scala.js Phantom.js launcher
70+
|var page = require('webpage').create();
71+
|var fs = require('fs');
72+
|var url = "${escapeJS(fixFileURI(webF.toURI).toASCIIString)}";
73+
|var autoExit = $autoExit;
74+
|page.onConsoleMessage = function(msg) {
75+
| console.log(msg);
76+
|};
77+
|page.onError = function(msg, trace) {
78+
| console.error(msg);
79+
| if (trace && trace.length) {
80+
| console.error('');
81+
| trace.forEach(function(t) {
82+
| console.error(' ' + t.file + ':' + t.line + (t.function ? ' (in function "' + t.function +'")' : ''));
83+
| });
84+
| }
85+
|
86+
| phantom.exit(2);
87+
|};
88+
|page.onCallback = function(data) {
89+
| if (!data.action) {
90+
| console.error('Called callback without action');
91+
| phantom.exit(3);
92+
| } else if (data.action === 'exit') {
93+
| phantom.exit(data.returnValue || 0);
94+
| } else if (data.action === 'setAutoExit') {
95+
| if (typeof(data.autoExit) === 'boolean')
96+
| autoExit = data.autoExit;
97+
| else
98+
| autoExit = true;
99+
| } else if (data.action == 'require.fs') {
100+
| if(data.method == 'separator') {
101+
| return JSON.stringify(fs.separator);
102+
| } else {
103+
| var ret = fs[data.method].apply(this, data.args);
104+
| return JSON.stringify(ret);
105+
| }
106+
| } else {
107+
| console.error('Unknown callback action ' + data.action);
108+
| phantom.exit(4);
109+
| }
110+
|};
111+
|page.open(url, function (status) {
112+
| if (autoExit || status !== 'success')
113+
| phantom.exit(status !== 'success');
114+
|});
115+
|""".stripMargin)
116+
} finally {
117+
out.close()
118+
}
119+
120+
logger.debug(
121+
"PhantomJS using launcher at: " + launcherTmpF.getAbsolutePath())
122+
123+
launcherTmpF
124+
}
125+
}
126+
}
127+
128+
object ScoveragePhantomJSEnv extends PhantomJSEnv {
129+
}
130+
131+

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.2")

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/shared/target/scala-2.11/classes")
5555

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

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package scalajssupport
2+
3+
import scala.scalajs.js
4+
import js.Dynamic.{ global => g }
5+
6+
class File(path: String) {
7+
import File._
8+
9+
val _file = jsFile(path)
10+
11+
def this(path: String, child: String) = {
12+
this(File.pathJoin(path, child))
13+
}
14+
15+
def delete(): Unit = {
16+
_file.delete()
17+
}
18+
def getAbsolutePath(): String = {
19+
_file.getAbsolutePath()
20+
}
21+
22+
def getName(): String = {
23+
_file.getName()
24+
}
25+
26+
def getPath(): String = {
27+
_file.getPath()
28+
}
29+
30+
def isDirectory(): Boolean = {
31+
_file.isDirectory()
32+
}
33+
34+
def mkdirs(): Unit = {
35+
_file.mkdirs()
36+
}
37+
38+
def listFiles(): Array[File] = {
39+
_file.listFiles().toArray
40+
}
41+
42+
def listFiles(filter: FileFilter): Array[File] = {
43+
_file.listFiles().filter(filter.accept).toArray
44+
}
45+
46+
def readFile(): String = {
47+
_file.readFile()
48+
}
49+
}
50+
51+
object File {
52+
val jsFile: JsFileObject = if (js.Dynamic.global.hasOwnProperty("Packages").asInstanceOf[Boolean])
53+
RhinoFile
54+
else if (!js.Dynamic.global.hasOwnProperty("window").asInstanceOf[Boolean])
55+
NodeFile
56+
else
57+
PhantomFile
58+
// Factorize this
59+
60+
def pathJoin(path: String, child: String): String =
61+
jsFile.pathJoin(path, child)
62+
63+
def write(path: String, data: String, mode: String = "a") =
64+
jsFile.write(path, data, mode)
65+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package scalajssupport
2+
3+
class FileWriter(file: File, append: Boolean) {
4+
def this(file: File) = this(file, false)
5+
def this(file: String) = this(new File(file), false)
6+
def this(file: String, append: Boolean) = this(new File(file), append)
7+
8+
def append(csq: CharSequence) = {
9+
File.write(file.getPath, csq.toString)
10+
this
11+
}
12+
13+
def close(): Unit = {
14+
// do nothing as we don't open a FD to the file, as phantomJS does not use FDs
15+
}
16+
17+
override def finalize(): Unit = close()
18+
19+
def flush() = {}
20+
}
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+
}

0 commit comments

Comments
 (0)