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