Hi,
We're about to start a long overdue reworking of the Gradle dependency DSL. By
'dependency DSL', I mean the DSL for declaring and working with project
dependencies, and declaring the outgoing publications of a project. It also
covers declaring artifact repositories.
There are a number of problems with the current DSL, which we want to fix
before we do a Gradle 1.0 release. I won't go into details here, except to
describe the first major problem we want to tackle.
The problem is a conceptual one, but a fundamental and important one:
Currently, you declare the dependencies of a project by grouping them into so
called 'configurations'. You also declare the outgoing publications of a
project by attaching them to configurations.
There are a few things wrong with this model.
Firstly, the name 'configuration' is meaningless - it doesn't tell you anything
about what the purpose or meaning of the thing is.
Secondly, this model couples the incoming and outgoing view of the project too
tightly. The reality is that the incoming dependencies of a project are not
always the same thing as the outgoing dependencies. For example, if a project
publishes a jar with some dependencies bundled in the jar (eg groovy-all.jar),
then the published runtime dependencies are different to the runtime
dependencies used at, say, test time. This becomes even more of a problem when
a project publishes multiple jars, each with a different runtime classpath.
So, the plan is to split what is currently the Configuration interface into 2
pieces:
* Something that represents a set of dependencies. These would be used to
declare the incoming dependencies of the project. Not sure about name for this
thing. Perhaps a 'dependency set'.
* Something that represents a set of published artifacts and their
dependencies. These would be used to declare the outgoing publications of the
project. This could be called a 'publication'.
The Configuration type and the configurations { } script block would be
removed. The DSL for declaring dependencies would stay pretty much the same as
it is now:
repositories { ... }
dependencies {
compile 'some:dep:1.0'
}
You will be able to declare custom dependency sets, similar to declaring custom
configurations now:
dependencies {
custom { transitive = false; description = 'some configuration' }
}
To resolve the dependencies, you'd do the same sort of thing you currently do
with a configuration:
copy { from dependencies.runtime; into 'libs' }
We might keep 'configurations' as a deprecated alias to 'dependencies', so you
will be able to do the following, while migrating to the new DSL:
copy { from configurations.runtime; into 'libs' }
From a model point of view, a DependencySet will have:
* a name
* a mutable collection of dependency instances
* a mutable collection of exclude rules
* a transitive flag
* some way to resolve the dependencies, either as a set of Files or as a set of
dependency meta-data.
Over time, we might further split this into a pure 'set of dependencies'
abstraction, and some kind of 'resolvable' abstraction.
Project.dependencies will be a container of these DependencySet instances.
So far, this is very similar to what we have already.
From a model point of view, a Publication will have:
* a name
* a mutable collection of artifact publication instances
* a set of DependencySet instances
* some way to resolve the publication, as a set of Files or as a set of
dependency meta-data.
Project.publications will be a container of these Publication instances.
By default, a project will have no publications. The java plugin would add a
default publication, containing the jar file and the contents of
dependencies.runtime as its runtime dependencies. You will be able to modify
this default publication, to change the set of artifacts or runtime
dependencies, or to add additional dependency sets.
You will also be able to add additional publications, configured however you
like.
The DSL might look something like:
publications {
main {
// add artifacts to the default publication
artifact srcJar
artifact 'some/file'
// change the published dependencies
dependencies {
runtime 'some:extra-dep:1.2'
}
}
// publish a separate fat jar
withDeps {
artifact fatJar
dependencies { runtime = [] }
}
}
This will replace the artifacts { } script block.
By default, a project dependency will translate into a dependency on the 'main'
publication. Initially, this will resolve to the artifacts of the publication,
plus all the runtime dependencies of the publication. Later, we plan to change
this so that it resolves to the 'api' dependencies at compile time, and the
'runtime' dependencies at runtime.
Each publication will be separately 'uploadable' to a repository. The
'upload<Config>' tasks will be replaced with 'publish<Publication>' tasks.
Initially, each Publish task instance will have a separate collection of
repositories attached to it, as Upload currently does. Later, we will look at
moving these off the task and into the model.
When publishing to an ivy repository, a publication is mapped to an ivy module
as follows:
* organisation is project.group
* module is project.name
* revision is project.version
* status is project.status
* each of the publication's dependency sets are mapped to an ivy configuration
* each of the publication's artifacts are mapped to an ivy artifact
Later, we will allow some customisation of this mapping, in particular:
* configurable ivy organisation, module and revision.
* some way to attach an artifact to particular ivy configurations.
We'll probably move this mapping to an 'ivy' plugin, which you will have to
explicitly apply to your project if you want to publish it as an ivy module.
When publishing to a maven repository, a publication is mapped to a maven
module as follows:
* groupId is project.group
* artifactId is project.name
* version is project.version
* dependency set 'runtime' maps to 'runtime' scope, 'api' to 'compile' scope,
and 'provided' to 'provided' scope.
* one of the publication's artifacts is mapped to the main artifact, the others
to classifier artifacts.
Again, we will allow some customisation of this mapping. And also, this mapping
will live in the 'maven' plugin, which you will have to explicitly apply if you
want to publish it as a maven module.
This is the first in a series of steps towards improving the DSL. I think the
next step is to make use of the publication concept to simplify how you publish
to a maven repository. More on this later.
--
Adam Murdoch
Gradle Developer
http://www.gradle.org
CTO, Gradle Inc. - Gradle Training, Support, Consulting
http://www.gradle.biz