On 9 May 2014, at 3:06 pm, Luke Daley <[email protected]> wrote:

> Hi,
> 
> I’m trying to bust the new plugin portal code out of core-impl and parts out 
> of core. I’m unsure about how to do this and avoid a circular dependency.
> 
> There are 3 parts:
> 
> 1. core - integrates plugin resolvers into the build lifecycle, provides 
> dependency management services needed for plugin resolution
> 2. general plugin infrastructure for plugin resolvers to use (e.g. interfaces 
> to implement)
> 3. specific plugin portal plugin resolver implementation
> 
> My plan was to create a new ‘plugin-portal’ project for #3, and put the 
> interfaces and support (#2) in ‘core’. Thus, circular dependency.
> 
> The way that core-impl solves this is through some service loader 
> indirection. I can see how we could do a similar thing in this case. The 
> ‘plugin-portal’ project could advertise a PluginResolver implementation that 
> ‘core’ loads at runtime. Therefore, ‘core’ would have no compile dependency 
> on ‘plugin-portal’. Is this the way to go?
> 
> One question then is how to order the plugin resolvers in core. If it just 
> loads them arbitrarily off the classpath, what orders them? One option would 
> be for the plugin portal resolver to be called out especially (e.g. it’s 
> loaded via some kind of marker interface that lives in core).
> 
> Any ideas?


The relationship between core and the dependency management stuff is actually a 
little different to this. You could think of the dependency management and 
plugin resolution capabilities being structured this way:

1. Public DSL and APIs through which you use the capability - defining 
repositories, dependencies, plugins, whatever.
2. These are backed by some internal services that do the work. These internal 
services are decoupled from the public types. They use their own request and 
response types. The services are injected into the public stuff.
3. The internal services have an implementation that provides some resolution 
algorithm.
4. The algorithm is backed by some internal resolver API that represent some 
source for the things being resolved.
5. There are a bunch of resolver implementations.

#2 is the contract between the DSL and the implementation, so this needs to be 
visible to everything. Ideally, #3 - #5 would not be visible from #1, and #1 
not visible from #3 - #5.

Currently, for dependency management, here’s what we do:

- #1 lives in core, because the dependency management DSL has references to 
core (eg via Configuration -> Buildable -> Task -> Project -> 
ConfigurationContainer and back).
- #2 lives in core, because the internal service API is not entirely decoupled 
from the DSL.
- #3, #4, and #5 live together in core-impl.

We use discovery to find #3 from #1, but not to find the resolver 
implementations - #3 takes care of that.

I would do something similar for the plugins: move the algorithm, the resolver 
API and resolver implementations out of core, inject some entry point service 
into core, and let the implementation of the entry point service take care of 
everything else.

The resolution algorithm and the resolver implementations don’t necessarily 
need to be separated from each other. I would keep them together for now.


--
Adam Murdoch
Gradle Co-founder
http://www.gradle.org
VP of Engineering, Gradleware Inc. - Gradle Training, Support, Consulting
http://www.gradleware.com

Join us for Gradle Summit 2014, June 12th and 13th in Santa Clara, CA: 
http://www.gradlesummit.com

Reply via email to