diff options
author | Som Snytt <som.snytt@gmail.com> | 2013-11-20 11:44:13 -0800 |
---|---|---|
committer | Som Snytt <som.snytt@gmail.com> | 2013-12-06 12:48:07 -0800 |
commit | 1d30ea86690db1b3b074190094d1f62d12e4efe1 (patch) | |
tree | d6ee4d131ec26f75083883ad0026e8b0c189aee6 /test | |
parent | 7d28c4966e5b32b46fda927f303aea4af20c4517 (diff) | |
download | scala-1d30ea86690db1b3b074190094d1f62d12e4efe1.tar.gz scala-1d30ea86690db1b3b074190094d1f62d12e4efe1.tar.bz2 scala-1d30ea86690db1b3b074190094d1f62d12e4efe1.zip |
SI-4841 Plugins get a class path
Let -Xplugin specify a class path (or multiple of them).
Each entry can be a jar or dir, and the first entry to supply
a plugin descriptor defines the plugin to load.
If no plugin is found on the path, then issue a warning if `-Xdev`.
This honors the legacy silent treatment (which scala-ide tests for).
In the proposed scheme, each plugin gets a class loader so that
plugins are isolated from each other.
Presumably, if compiler plugins were a rich ecosystem, in which
shared dependencies were required in incompatible versions, this
would have become a requirement by now.
(Updated with a `DirectTest` that uses two plugins, but keeping
the following as documentation.)
Partest can't do multiple plugins yet, but this is what it looks like:
```
skalac -Xplugin:sample.jar:useful.jar:util,needful.jar:another.jar:util,needful.jar:util:exploded -Xplugin-require:sample,another,other foo.scala
skalac -Xplugin:sample.jar:useful.jar:util,needful.jar:another.jar:util,needful.jar:util:exploded -Xplugin-require:sample,other -Xplugin-disable:another foo.scala
skalac -Xplugin:sample.jar:useful.jar:util,sample.jar:useful.jar:util -Xplugin-require:sample foo.scala
```
The manual test shows three plugins with various permutations of jars and dirs.
The manual test demonstrates that plugins only see classes on their class path:
```
Initializing test.plugins.SamplePlugin
needful.Needful? Failure(java.lang.ClassNotFoundException: needful.Needful)
useful.Useful? Success(class useful.Useful)
Initializing more.plugins.AnotherPlugin
needful.Needful? Success(class needful.Needful)
useful.Useful? Failure(java.lang.ClassNotFoundException: useful.Useful)
Initializing other.plugins.OtherPlugin
```
Disabling a plugin results in a message instead of silent suppression:
```
Disabling plugin another
```
The duplicate plugin class test must still be honored:
```
Ignoring duplicate plugin sample (test.plugins.SamplePlugin)
Initializing test.plugins.SamplePlugin
needful.Needful? Failure(java.lang.ClassNotFoundException: needful.Needful)
useful.Useful? Success(class useful.Useful)
```
If the path is bad, then missing classes will report which plugin induced
the error:
```
Error: class not found: util/Probe required by test.plugins.SamplePlugin
Error: class not found: util/Probe required by more.plugins.AnotherPlugin
Initializing other.plugins.OtherPlugin
needful.Needful? Success(class needful.Needful)
useful.Useful? Failure(java.lang.ClassNotFoundException: useful.Useful)
error: Missing required plugin: sample
error: Missing required plugin: another
two errors found
```
Diffstat (limited to 'test')
-rwxr-xr-x | test/files/neg/t6446-missing.check | 2 | ||||
-rw-r--r-- | test/files/run/t4841-isolate-plugins.check | 2 | ||||
-rw-r--r-- | test/files/run/t4841-isolate-plugins/ploogin.scala | 30 | ||||
-rw-r--r-- | test/files/run/t4841-isolate-plugins/t4841-isolate-plugin.scala | 39 | ||||
-rw-r--r-- | test/files/run/t4841-no-plugin.check | 1 | ||||
-rw-r--r-- | test/files/run/t4841-no-plugin.scala | 17 |
6 files changed, 90 insertions, 1 deletions
diff --git a/test/files/neg/t6446-missing.check b/test/files/neg/t6446-missing.check index cd867289c3..029c8057c3 100755 --- a/test/files/neg/t6446-missing.check +++ b/test/files/neg/t6446-missing.check @@ -1,4 +1,4 @@ -Warning: class not found: t6446.Ploogin +Error: unable to load class: t6446.Ploogin phase name id description ---------- -- ----------- parser 1 parse source into ASTs, perform simple desugaring diff --git a/test/files/run/t4841-isolate-plugins.check b/test/files/run/t4841-isolate-plugins.check new file mode 100644 index 0000000000..a6462b424b --- /dev/null +++ b/test/files/run/t4841-isolate-plugins.check @@ -0,0 +1,2 @@ +My phase name is ploogin1_1 +My phase name is ploogin1_2 diff --git a/test/files/run/t4841-isolate-plugins/ploogin.scala b/test/files/run/t4841-isolate-plugins/ploogin.scala new file mode 100644 index 0000000000..bd8c7275ec --- /dev/null +++ b/test/files/run/t4841-isolate-plugins/ploogin.scala @@ -0,0 +1,30 @@ + +package t4841 + +import scala.tools.nsc.{ Global, Phase } +import scala.tools.nsc.plugins.{ Plugin, PluginComponent } +import scala.reflect.io.Path +import scala.reflect.io.File + +/** A test plugin. */ +class Ploogin(val global: Global, val name: String = "ploogin") extends Plugin { + import global._ + + val description = "A sample plugin for testing." + val components = List[PluginComponent](TestComponent) + + private object TestComponent extends PluginComponent { + val global: Ploogin.this.global.type = Ploogin.this.global + //override val runsBefore = List("refchecks") + val runsAfter = List("jvm") + val phaseName = Ploogin.this.name + override def description = "A sample phase that does so many things it's kind of hard to describe briefly." + def newPhase(prev: Phase) = new TestPhase(prev) + class TestPhase(prev: Phase) extends StdPhase(prev) { + override def description = TestComponent.this.description + def apply(unit: CompilationUnit) { + if (settings.developer) inform(s"My phase name is $phaseName") + } + } + } +} diff --git a/test/files/run/t4841-isolate-plugins/t4841-isolate-plugin.scala b/test/files/run/t4841-isolate-plugins/t4841-isolate-plugin.scala new file mode 100644 index 0000000000..5421922c9c --- /dev/null +++ b/test/files/run/t4841-isolate-plugins/t4841-isolate-plugin.scala @@ -0,0 +1,39 @@ + +import tools.nsc.plugins.PluginDescription +import tools.partest.DirectTest + +import java.io.File + +// show that plugins are on isolated class loaders +object Test extends DirectTest { + override def code = "class Code" + + override def extraSettings = s"-usejavacp" + + // plugin named ploogin1_1 or ploogin1_2, but not ploogin2_x + // Although the samples are in different classloaders, the plugin + // loader checks for distinctness by class name, so the names must differ. + def pluginCode(index: Int) = s""" + |package t4841 { + | class SamplePloogin$index(global: scala.tools.nsc.Global) extends Ploogin(global, s"$${PlooginCounter.named}_$index") + | object PlooginCounter { + | val count = new java.util.concurrent.atomic.AtomicInteger + | def named = s"ploogin$${count.incrementAndGet}" + | } + |}""".stripMargin.trim + + def compilePlugin(i: Int) = { + val out = (testOutput / s"p$i").createDirectory() + val args = Seq("-usejavacp", "-d", out.path) + compileString(newCompiler(args: _*))(pluginCode(i)) + val xml = PluginDescription(s"p$i", s"t4841.SamplePloogin$i").toXML + (out / "scalac-plugin.xml").toFile writeAll xml + out + } + + override def show() = { + val dirs = 1 to 2 map (compilePlugin(_)) + compile("-Xdev", s"-Xplugin:${dirs mkString ","}", "-usejavacp", "-d", testOutput.path) + } +} + diff --git a/test/files/run/t4841-no-plugin.check b/test/files/run/t4841-no-plugin.check new file mode 100644 index 0000000000..4338f0ce23 --- /dev/null +++ b/test/files/run/t4841-no-plugin.check @@ -0,0 +1 @@ +warning: No plugin in path t4841-no-plugin-run.obj/plugins.partest diff --git a/test/files/run/t4841-no-plugin.scala b/test/files/run/t4841-no-plugin.scala new file mode 100644 index 0000000000..d91bf7ee21 --- /dev/null +++ b/test/files/run/t4841-no-plugin.scala @@ -0,0 +1,17 @@ + +import tools.partest.DirectTest + +import java.io.File + +// warn only if no plugin on Xplugin path +object Test extends DirectTest { + override def code = "class Code" + + override def extraSettings = s"-usejavacp -d ${testOutput.path}" + + override def show() = { + val tmp = new File(testOutput.jfile, "plugins.partest").getAbsolutePath + compile("-Xdev", s"-Xplugin:$tmp", "-Xpluginsdir", tmp) + } +} + |