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 /src/compiler/scala/tools/nsc/plugins/Plugins.scala | |
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 'src/compiler/scala/tools/nsc/plugins/Plugins.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/plugins/Plugins.scala | 21 |
1 files changed, 14 insertions, 7 deletions
diff --git a/src/compiler/scala/tools/nsc/plugins/Plugins.scala b/src/compiler/scala/tools/nsc/plugins/Plugins.scala index 4769705404..12f9aeba27 100644 --- a/src/compiler/scala/tools/nsc/plugins/Plugins.scala +++ b/src/compiler/scala/tools/nsc/plugins/Plugins.scala @@ -8,6 +8,7 @@ package scala.tools.nsc package plugins import scala.reflect.io.{ File, Path } +import scala.tools.nsc.util.ClassPath import scala.tools.util.PathResolver.Defaults /** Support for run-time loading of compiler plugins. @@ -16,8 +17,7 @@ import scala.tools.util.PathResolver.Defaults * @version 1.1, 2009/1/2 * Updated 2009/1/2 by Anders Bach Nielsen: Added features to implement SIP 00002 */ -trait Plugins { - self: Global => +trait Plugins { global: Global => /** Load a rough list of the plugins. For speed, it * does not instantiate a compiler run. Therefore it cannot @@ -25,13 +25,20 @@ trait Plugins { * filtered from the final list of plugins. */ protected def loadRoughPluginsList(): List[Plugin] = { - val jars = settings.plugin.value map Path.apply - def injectDefault(s: String) = if (s.isEmpty) Defaults.scalaPluginPath else s - val dirs = (settings.pluginsDir.value split File.pathSeparator).toList map injectDefault map Path.apply - val maybes = Plugin.loadAllFrom(jars, dirs, settings.disable.value) + def asPath(p: String) = ClassPath split p + val paths = settings.plugin.value filter (_ != "") map (s => asPath(s) map Path.apply) + val dirs = { + def injectDefault(s: String) = if (s.isEmpty) Defaults.scalaPluginPath else s + asPath(settings.pluginsDir.value) map injectDefault map Path.apply + } + val maybes = Plugin.loadAllFrom(paths, dirs, settings.disable.value) val (goods, errors) = maybes partition (_.isSuccess) // Explicit parameterization of recover to suppress -Xlint warning about inferred Any - errors foreach (_.recover[Any] { case e: Exception => inform(e.getMessage) }) + errors foreach (_.recover[Any] { + // legacy behavior ignores altogether, so at least warn devs + case e: MissingPluginException => if (global.isDeveloper) warning(e.getMessage) + case e: Exception => inform(e.getMessage) + }) val classes = goods map (_.get) // flatten // Each plugin must only be instantiated once. A common pattern |