diff --git a/README.md b/README.md index 003c7f1..901b5f0 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ The following options are provided: Option | Description ----------------------------|------------ command | The filesystem location of the command to execute. Commands such as "node" default to being known to your path. However there path can be supplied here." -engineType | The type of engine to use i.e. CommonNode, Node, PhantomJs, Rhino, Trireme, or AutoDetect. The default is AutoDetect, which uses Node if installed or otherwise falls back to Trireme. +engineType | The type of engine to use i.e. CommonNode, Node, PhantomJs, Rhino or AutoDetect. The default is AutoDetect, which uses Node if installed or otherwise falls back to Rhino. npmPreferSystemInstalledNpm | Prefer detecting and using locally installed NPM when using a local engine that provides Node support. Defaults to true. npmSubcommand | The subcommand that NPM should use i.e. Install, Update, Ci. Defaults to Update. @@ -52,8 +52,6 @@ is found in the project's base directory then it will cause npm to run. npm extracts its artifacts into the `node_modules` folder of a base directory and makes the contents available to sbt-web plugins as a whole. Note that sbt-js-engines loads the actual source code of npm via a WebJar and invokes an "npm update". Any external npm activity can therefore be performed interchangeably with sbt-js-engine in place. -> Note that the npm functionality requires JDK 7 when running Trireme given the additional file system support required. If JDK 6 is required then use Node as the engine. - # Releasing sbt-js-engine 1. Tag the release: `git tag -s 1.2.3` diff --git a/build.sbt b/build.sbt index abb01e6..01b7209 100644 --- a/build.sbt +++ b/build.sbt @@ -20,11 +20,8 @@ libraryDependencies ++= Seq( "org.specs2" %% "specs2-scalacheck" % "4.23.0" % "test", "io.spray" %% "spray-json" % "1.3.6", - // Trireme - "io.apigee.trireme" % "trireme-core" % "0.9.4", - "io.apigee.trireme" % "trireme-node10src" % "0.9.4", - // NPM + // TODO: npm can finally be upgraded here "org.webjars" % "npm" % "5.0.0-2", // we are currently stuck: https://github.com/webjars/webjars/issues/1926 "org.webjars" % "webjars-locator-core" % "0.59", diff --git a/src/main/scala/com/typesafe/sbt/jse/SbtJsEngine.scala b/src/main/scala/com/typesafe/sbt/jse/SbtJsEngine.scala index bff2fb4..9694dfe 100644 --- a/src/main/scala/com/typesafe/sbt/jse/SbtJsEngine.scala +++ b/src/main/scala/com/typesafe/sbt/jse/SbtJsEngine.scala @@ -18,11 +18,11 @@ object JsEngineImport { object JsEngineKeys { object EngineType extends Enumeration { - val CommonNode, Node, PhantomJs, Javax, Rhino, Trireme, + val CommonNode, Node, PhantomJs, Javax, Rhino, /** * Auto detect the best available engine to use for most common tasks - this will currently select node if - * available, otherwise it will fall back to trireme + * available, otherwise it will fall back to Rhino */ AutoDetect = Value } @@ -71,11 +71,10 @@ object SbtJsEngine extends AutoPlugin { case EngineType.PhantomJs => PhantomJs(command) case EngineType.Javax => JavaxEngine() case EngineType.Rhino => Rhino() - case EngineType.Trireme => Trireme(stdEnvironment = env) case EngineType.AutoDetect => if (autoDetectNode(command)) { Node(command, stdEnvironment = env) } else { - Trireme(stdEnvironment = env) + Rhino() } } } @@ -88,7 +87,7 @@ object SbtJsEngine extends AutoPlugin { val nodeExists = Try(Process(s"${LocalEngine.path(command, "node")} --version").!!).isSuccess if (!nodeExists) { println("!!!") - println("Warning: node.js detection failed, sbt will use the Rhino based Trireme JavaScript engine instead to run JavaScript assets compilation, which in some cases may be orders of magnitude slower than using node.js.") + println("Warning: node.js detection failed, sbt will use the Rhino JavaScript engine instead to run JavaScript assets compilation, which in some cases may be orders of magnitude slower than using node.js.") println("!!!") } nodeExists diff --git a/src/main/scala/com/typesafe/sbt/jse/engines/Trireme.scala b/src/main/scala/com/typesafe/sbt/jse/engines/Trireme.scala deleted file mode 100644 index 1ef1ea0..0000000 --- a/src/main/scala/com/typesafe/sbt/jse/engines/Trireme.scala +++ /dev/null @@ -1,78 +0,0 @@ -package com.typesafe.sbt.jse.engines - -import java.io._ -import java.util.concurrent.{ForkJoinPool, TimeUnit} - -import scala.collection.immutable -import scala.jdk.CollectionConverters.* -import scala.concurrent.duration._ -import io.apigee.trireme.core._ -import org.mozilla.javascript.RhinoException - -import scala.concurrent.ExecutionException -import scala.util.control.NonFatal - -class Trireme( - stdArgs: immutable.Seq[String], - stdEnvironment: Map[String, String] -) extends Engine { - - private val AwaitTerminationTimeout = 1.second - - override def executeJs(source: File, args: immutable.Seq[String], environment: Map[String, String], - stdOutSink: String => Unit, stdErrSink: String => Unit): JsExecutionResult = { - - val file = source.getCanonicalFile - - val env = (sys.env ++ stdEnvironment ++ environment).asJava - val sandbox = new Sandbox() - sandbox.setAsyncThreadPool(ForkJoinPool.commonPool()) - val nodeEnv = new NodeEnvironment() - nodeEnv.setSandbox(sandbox) - sandbox.setStdin(new ByteArrayInputStream(Array())) - sandbox.setStdout(new LineSinkOutputStream(stdOutSink)) - val stderrOs = new LineSinkOutputStream(stdErrSink) - sandbox.setStderr(stderrOs) - - val script = nodeEnv.createScript(file.getName, file, (stdArgs ++ args).toArray) - script.setEnvironment(env) - - try { - val status = script.execute.get() - if (status.hasCause) { - handleError(status.getCause, stderrOs) - } else { - JsExecutionResult(0) - } - } catch { - case NonFatal(e) => handleError(e, stderrOs) - } finally { - script.close() - nodeEnv.getScriptPool.shutdown() - nodeEnv.getScriptPool.awaitTermination(AwaitTerminationTimeout.toMillis, TimeUnit.MILLISECONDS) - } - } - - private def handleError(error: Throwable, stderrOs: OutputStream): JsExecutionResult = { - error match { - case ee: ExecutionException => - handleError(ee.getCause, stderrOs) - case e: RhinoException => - stderrOs.write(e.getLocalizedMessage.getBytes("UTF-8")) - stderrOs.write(e.getScriptStackTrace.getBytes("UTF-8")) - JsExecutionResult(1) - case t => - t.printStackTrace(new PrintStream(stderrOs)) - JsExecutionResult(1) - } - } - - override def isNode: Boolean = true -} - -object Trireme { - def apply( - stdArgs: immutable.Seq[String] = Nil, - stdEnvironment: Map[String, String] = Map.empty - ): Trireme = new Trireme(stdArgs, stdEnvironment) -} \ No newline at end of file diff --git a/src/test/scala/com/typesafe/sbt/jse/engines/TriremeSpec.scala b/src/test/scala/com/typesafe/sbt/jse/engines/TriremeSpec.scala deleted file mode 100644 index 18c2622..0000000 --- a/src/test/scala/com/typesafe/sbt/jse/engines/TriremeSpec.scala +++ /dev/null @@ -1,91 +0,0 @@ -package com.typesafe.sbt.jse.engines - -import org.specs2.mutable.Specification -import java.io.File -import scala.collection.immutable - -class TriremeSpec extends Specification { - - sequential - - "The Trireme engine" should { - "execute some javascript by passing in a string arg and comparing its return value" in { - val f = new File(classOf[TriremeSpec].getResource("test-node.js").toURI) - val out = new StringBuilder - val err = new StringBuilder - Trireme().executeJs(f, immutable.Seq("999"), Map.empty, out.append(_), err.append(_)) - err.toString.trim must_== "" - out.toString.trim must_== "999" - } - - "execute some javascript by passing in a string arg and comparing its return value expecting an error" in { - val f = new File(classOf[TriremeSpec].getResource("test-rhino.js").toURI) - val out = new StringBuilder - val err = new StringBuilder - Trireme().executeJs(f, immutable.Seq("999"), Map.empty, out.append(_), err.append(_)) - out.toString.trim must_== "" - err.toString.trim must startWith("""ReferenceError: "readFile" is not defined""") - } - } - - private def runSimpleTest() = { - val f = new File(classOf[TriremeSpec].getResource("test-node.js").toURI) - val out = new StringBuilder - val err = new StringBuilder - Trireme().executeJs(f, immutable.Seq("999"), Map.empty, out.append(_), err.append(_)) - err.toString.trim must_== "" - out.toString.trim must_== "999" - } - - "not leak threads" in { - // this test assumes that there are no other trireme tests running concurrently, if there are, the trireme thread - // count will be non 0 - runSimpleTest() - - Thread.sleep(5) // locally 1ms is enough, but it seems ci server needs a bit more time - - import scala.jdk.CollectionConverters.* - val triremeThreads = Thread.getAllStackTraces.keySet.asScala - .filter(_.getName.contains("Trireme")) - - ("trireme threads: " + triremeThreads) <==> (triremeThreads.size === 0) - ok - } - - "not leak file descriptors" in { - import java.lang.management._ - val os = ManagementFactory.getOperatingSystemMXBean - try { - // To get the open file descriptor count, need to check if it exists - os.getClass.getMethod("getOpenFileDescriptorCount") - - // brew a little first - runSimpleTest() - runSimpleTest() - runSimpleTest() - runSimpleTest() - - val openFds = UnixGetOpenFileDescriptors.getCount() - runSimpleTest() - - UnixGetOpenFileDescriptors.getCount() must_== openFds - } catch { - case _: NoSuchMethodException => - println("Skipping file descriptor leak test because OS mbean doesn't have getOpenFileDescriptorCount") - ok - } - } -} - -// This is in a separate object so that it only gets loaded when we call it, avoiding class not found -// in Windows -object UnixGetOpenFileDescriptors { - import java.lang.management.ManagementFactory - import com.sun.management.UnixOperatingSystemMXBean - - private val os = ManagementFactory.getOperatingSystemMXBean - def getCount(): Long = { - os.asInstanceOf[UnixOperatingSystemMXBean] - .getMaxFileDescriptorCount - } -}