Skip to content

SI-4841 Plugins get a class path#3169

Merged
retronym merged 1 commit intoscala:masterfrom
som-snytt:issue/4841-plugin-cp
Dec 12, 2013
Merged

SI-4841 Plugins get a class path#3169
retronym merged 1 commit intoscala:masterfrom
som-snytt:issue/4841-plugin-cp

Conversation

@som-snytt
Copy link
Contributor

@som-snytt som-snytt commented Nov 20, 2013

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.

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, this would
have become a requirement by now.

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

fixes scala/bug#4841

@som-snytt
Copy link
Contributor Author

There is some cognitive dissonance in the plugin feature, in that a missing plugin is a warning unless you specify -Xplugin-require. While the "extension directory" mechanism -Xpluginsdir does suggest I might be compiling with some unknown set of installed plugins (perhaps mandated by the team, for instance), if I ask for a plugin to run with -Xplugin, probably I really mean that I don't want to compile without it.

@som-snytt
Copy link
Contributor Author

typesafeDummy?

@adriaanm
Copy link
Contributor

our self-deprecating sense of humo(u)r -- part of the maven task that goes looking for an artifact. "Build failure" just means "artifact not found, kthx!"

@som-snytt

This comment has been minimized.

@scala-jenkins

This comment has been minimized.

@som-snytt
Copy link
Contributor Author

Rebased around the removal of Pair.

...and a partridge in a Pair Tree.

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
```
@som-snytt
Copy link
Contributor Author

Updated not to bail on -Xplugin:garbage, which scala-ide tests for. It will warn if -Xdev, because, dude, I said -Xplugin because I want a plugin. There is no flag to turn on a message if -Xplugindirs is void of plugins. Also added a test with two sample plugins going head-to-head.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still throws on error instead of reporting.

@som-snytt
Copy link
Contributor Author

Review by @adriaanm perhaps, who touched plugins code once has already commented in an aside. Or, he is also good at delegating.

@som-snytt
Copy link
Contributor Author

I see we were just bumped to critical. Possibly, any issues under Si-5000 are grandfathered into criticality. But Adriaan may be too busy delegating to delegate the review. Plus I think I noticed he has an upcoming meetup.

@som-snytt
Copy link
Contributor Author

I know @retronym enjoys a good test. He has seen everything under the sun, no doubt; but this is more like strolling into a carnival to watch an amateur, not even a magician or high wire act, but some guy who bends over backward to walk on his hands. That's kind of entertaining, right?

@adriaanm
Copy link
Contributor

Criticality was my JIRA bulk edit device. Trying to machete my way through without turning into the hulk editor.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PluginLoadException should wrap the underlying exception as its cause.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was responsible for the previous iteration, too. I don't remember before that (fail silently?) but I do remember wondering if people want to see a stack trace about a missing class, that says "ClassNotFound". By people, I mean the guy who takes up support for continuations plugin and can't get the class path right in sbt, or whatever. In Plugins, it recover[Any]s and just uses the message, which would include the causative message IIUC.

@retronym
Copy link
Member

Highly entraining feats of contortionism. My only comment was really about old code, so:
LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants