On 07/02/2011, at 1:27 AM, Peter Niederwieser wrote:

> 
> Once we get to the point where plugins no longer all come with the
> distribution, we will certainly have to get this right.

Absolutely. This is a problem which pretty much every plugin has, so we want to 
provide some general purpose solution to it, that we can use for the built-in 
plugins as well as external plugins.

At the moment, each plugin takes a different approach to this problem. It would 
be good if we could clean this up a bit. Some examples:

* Infer the version from the environment. For example, the java plugin uses the 
current jvm  to decide which java compiler to use, or which jvm to run the 
tests under.

* Infer the version from the dependencies of the project. For example, the java 
plugin uses the version of JUnit, TestNG (and Spock and so on, etc) declared in 
the testRuntime classpath to run the tests.

* Infer the version from a specially named configuration. For example, the 
groovy plugin uses the version of Groovy declared in the 'groovy' configuration 
to decide which groovy compiler to use. The scala and antlr plugins do the same.

* Use a hardcoded version, included in the distribution. For example, the jetty 
plugin uses a hardcoded version of Jetty. The code-quality plugin does the same.

* Use a convention property. For example, the java plugin uses the 
'sourceCompatibility' property to decide which version of the Java language to 
compile for (as opposed to the implementation, which defaults to the current 
jvm).

I can see there are a few aspects to this problem:

* A tool may provide some API which is visible in the source code. Examples 
include languages such as Java, Groovy, Antlr, and test frameworks such as 
JUnit, and runtime containers, such as a web container. The plugin must ensure 
that the correct API is included in the compile classpath.

* An implementation of the tool may be used do some work at build time. For 
example, the Groovy compiler is used at build time. A tool may have multiple 
implementations which support a given version of its API. Or a given 
implementation may support multiple versions of the API. For example, there are 
many javac implementations which can handle the Java 5 API, and a given javac 
implementation can handle multiple versions of the Java API. The plugin must 
ensure that the appropriate implementation is used at build time.

* An implementation of the tool may add runtime dependencies to the project. 
For example, the Antlr compiler generates code which requires a particular 
implementation jar at runtime. The plugin must ensure that the correct runtime 
dependency is added to the runtime classpath.

* An implementation of the tool may be used at runtime. For example, the Jetty 
plugin uses a particular implementation of the web container spec at runtime. 
The plugin must ensure that the correct implementation is used at runtime.

A good solution should:

* Allow me to simply specify which version of a tool API I need, and have the 
plugin provide default implementations at each of the above points.

* Provide default implementations for those tools which do not provide an API 
(Checkstyle, CodeNarc, etc).

* Allow me to easily specify which implementation I want to use, and have the 
plugin use this implementation at each of the above points. This should include 
not just which implementation to use, but where to find it (installed at some 
location, download from a repo, etc).

* Allow me to override the implementation independently at each and every point 
above.

* Use a consistent approach to declaring the tool API and implementations to 
use. This approach should work consistently for everything: languages 
(including Java), code quality tools, test frameworks, runtime containers, etc.

I'm not sure about default versions for APIs. I'd say this is not such a good 
idea. We could always add another plugin which adds default versions and 
locations for common tools.

An option is to use the dependency declarations for those tools with an API. 
For example, this implies that Groovy 1.7.7 API and implementation should be 
used:

repositories {
    // some repo to download the impl from
}

dependencies {
    compile 'org.codehaus.groovy:groovy:1.7.7'
}

Or, perhaps something like this, which would also imply where to get the impl 
from:

dependencies {
    compile groovy('1.7.7')
}

This approach would also allow something like the Jetty plugin to decide which 
version of Jetty to use:

dependencies {
    compile servlet('3.0') // might imply use Jetty 8 by default
    compile servlet('2.5') // might imply use Jetty 7 by default
}

Each tool would also have a separate implementation configuration, which you 
can configure if desired:

dependencies {
    compile groovy('1.7.7')
    groovyTools fileTree('some/custom/groovy/impl')
}

This also allows you to query which implementation is used, so you can, for 
example, include this in a report, or reproduce a particular build.


--
Adam Murdoch
Gradle Developer
http://www.gradle.org
CTO, Gradle Inc. - Gradle Training, Support, Consulting
http://www.gradle.biz

Reply via email to