diff --git a/src/main/scala/sbt/ProjectMatrix.scala b/src/main/scala/sbt/ProjectMatrix.scala index d98148637..6563457fe 100644 --- a/src/main/scala/sbt/ProjectMatrix.scala +++ b/src/main/scala/sbt/ProjectMatrix.scala @@ -4,6 +4,7 @@ import java.util.Locale import scala.collection.immutable.ListMap import Keys._ import sbt.librarymanagement.CrossVersion.partialVersion +import scala.util.Try /** * A project matrix is an implementation of a composite project @@ -210,8 +211,23 @@ object ProjectMatrix { jsPlatform(scalaVersions, Nil) override def jsPlatform(scalaVersions: Seq[String], settings: Seq[Setting[_]]): ProjectMatrix = - custom(jsIdSuffix, jsDirectorySuffix, scalaVersions, { _.settings(settings) }) - + custom(jsIdSuffix, jsDirectorySuffix, scalaVersions, + { _ + .enablePlugins(scalajsPlugin(this.getClass.getClassLoader).getOrElse( + sys.error("""Scala.js plugin was not found. Add the sbt-scalajs plugin into project/plugins.sbt: + | addSbtPlugin("org.scala-js" % "sbt-scalajs" % "x.y.z") + |""".stripMargin) + )) + .settings(settings) + }) + + def scalajsPlugin(classLoader: ClassLoader): Try[AutoPlugin] = { + import sbtprojectmatrix.ReflectionUtil._ + withContextClassloader(classLoader) { loader => + getSingletonObject[AutoPlugin](loader, "org.scalajs.sbtplugin.ScalaJSPlugin$") + } + } + override def js: ProjectFinder = new SuffixBaseProjectFinder(jsIdSuffix) override def crossLibrary(scalaVersions: Seq[String], suffix: String, settings: Seq[Setting[_]]): ProjectMatrix = diff --git a/src/main/scala/sbtprojectmatrix/ReflectionUtil.scala b/src/main/scala/sbtprojectmatrix/ReflectionUtil.scala new file mode 100644 index 000000000..77081ec6f --- /dev/null +++ b/src/main/scala/sbtprojectmatrix/ReflectionUtil.scala @@ -0,0 +1,36 @@ +package sbtprojectmatrix + +import java.lang.reflect.InvocationTargetException +import scala.reflect.ClassTag +import scala.util.Try + +object ReflectionUtil { + def getSingletonObject[A: ClassTag](classLoader: ClassLoader, className: String): Try[A] = + Try { + val clazz = classLoader.loadClass(className) + val t = implicitly[ClassTag[A]].runtimeClass + Option(clazz.getField("MODULE$").get(null)) match { + case None => throw new ClassNotFoundException(s"Unable to find $className using classloader: $classLoader") + case Some(c) if !t.isInstance(c) => throw new ClassCastException(s"${clazz.getName} is not a subtype of $t") + case Some(c: A) => c + } + } + .recover { + case i: InvocationTargetException if i.getTargetException != null => throw i.getTargetException + } + + def objectExists(classLoader: ClassLoader, className: String): Boolean = + try { + classLoader.loadClass(className).getField("MODULE$").get(null) != null + } catch { + case _: Throwable => false + } + + def withContextClassloader[A](loader: ClassLoader)(body: ClassLoader => A): A = { + val current = Thread.currentThread().getContextClassLoader + try { + Thread.currentThread().setContextClassLoader(loader) + body(loader) + } finally Thread.currentThread().setContextClassLoader(current) + } +} diff --git a/src/sbt-test/projectMatrix/js/project/plugins.sbt b/src/sbt-test/projectMatrix/js/project/plugins.sbt index 4e80bbafc..70858c7d8 100644 --- a/src/sbt-test/projectMatrix/js/project/plugins.sbt +++ b/src/sbt-test/projectMatrix/js/project/plugins.sbt @@ -3,3 +3,4 @@ sys.props.get("plugin.version") match { case _ => sys.error("""|The system property 'plugin.version' is not defined. |Specify this property using the scriptedLaunchOpts -D.""".stripMargin) } +addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.27") diff --git a/src/sbt-test/projectMatrix/js/test b/src/sbt-test/projectMatrix/js/test index 8ade538b7..553c6bf3a 100644 --- a/src/sbt-test/projectMatrix/js/test +++ b/src/sbt-test/projectMatrix/js/test @@ -1,4 +1,5 @@ -> compile +> fastOptJS -$ exists core/target/js-2.12/classes/a/Core.class -$ exists core/target/js-2.11/classes/a/Core.class +$ exists app/target/js-2.12/app-fastopt.js +$ exists core/target/js-2.12/core-fastopt.js +$ exists core/target/js-2.11/core-fastopt.js