Hans Dockter wrote:
On Aug 22, 2009, at 12:46 AM, Adam Murdoch wrote:
Hans Dockter wrote:
On Aug 1, 2009, at 6:40 PM, Steve Appling wrote:
I would like to use the java multiproject sample in an integration
test for the new build* tasks that can include dependents or
dependees (still REALLY need good names for these). Currently both
the :api and the :services:webservice project have a project
execution dependency on the :shared project (a Project.dependsOn
'shared'). This will defeat the changes I am making, it forces
test in :api to depend on test in :shared. Is there a need for
these two project to have a project execution dependency - I would
like to remove it.
Those dependsOn declarations were historic residues. Good that you
have removed them.
Another note. I find the term Project Dependency used
inconsistently in the users guide. Project dependencies as
described in section 29.6.1.3 refers to a "Project.dependsOn"
relationship. I think these are called project execution
dependencies in other areas of the user guide.
Section 26.3.4 also describes "Project Dependencies", but these are
the "dependencies { compile project(':shared') }" type of
dependency which is very different. This is called a project lib
dependency in other parts of the user guide (although I think I
like project artifact dependency better).
These are still confusingly similar - I have found myself
discussing project dependency with someone at my company and we
were each referring to different types of project dependencies. I
don't really have more discriminating names than what I described
above, however.
If I have the correct terminologies here, I'll update the user
guide to make these consistent when I check in documentation for
the Java Plugin task changes I am making.
I'm not sure about the best terminology here. One way of phrasing is
would be to call project.dependsOn a project dependency and
<someConf> project('a') a project artifact dependency. But the
latter is much more common than the first. So using project
execution dependencies and project dependencies might be the best
way of doing things. Updating the user's guide would be excellent.
I'm wondering if we should get rid of Project.dependsOn(), and just
leave Project.evaluationDependsOn(). Is there a good use case which
project artifact dependencies does not solve?
One use case is our own multi-project build. Without project execution
dependencies we need to write in the root project:
clean.dependsOn subprojects*.clean
task javadoc(overwrite: true, dependsOn: subprojects*.javadoc)
task groovydoc(overwrite: true, dependsOn: subprojects*.groovydoc)
task check(overwrite: true, dependsOn: subprojects*.check)
task test(overwrite: true, dependsOn: subprojects*.test)
If we declare project execution dependencies from root to the
children, we can do:
dependsOnChildren()
task javadoc(overwrite: true)
task groovydoc(overwrite: true)
task check(overwrite: true)
task test(overwrite: true)
So we get the aggregation behavior for free.
But it doesn't actually work particularly well:
* You get a lot of unwanted dependencies.
For example, the :javadoc task doesn't actually depend on the
:gradle-core:javadoc or :gradle-wrapper:javadoc tasks, but adding
dependsOnChildren() forces me to always build the javadoc for all
subprojects, even though I am only ever interested in the javadocs
produced by :javadoc
Another example: If the root project happens to have some production
source of its own, using dependsOnChildren() means I cannot clean or
compile or check or test or jar just the stuff for the root project. I
have to clean or compile or check or test or jar the all subprojects as
well, even though I'm not interested in the result.
* The actual dependencies are missing from the model.
There's nothing in the configurations of the root project which reflect
the artifacts that the root project actually uses. Which means Gradle
can't do any of the good stuff it does for project artifact
dependencies, such as honouring the -a option. It means that
:buildDependents doesn't build anything, even though the root project
actually does depend on all its subprojects. It means that
:gradle-core:buildNeeded doesn't build the root project, even though the
root project actually depends on :gradle-core.
* It forces the same lifecycle on both the aggregating project and the
aggregated project.
These are the exact same problems we've been solving in the Java plugin,
for inter-project dependencies for Java projects. We've been moving away
from dependsOn() for Java project, because it just doesn't model the
actual build very well. Instead, we've been using artifact dependencies
to drive task dependencies. We've also been separating lifecycle and
worker tasks, so that worker tasks only depend on the tasks which
produce the artifacts they need, and lifecycle tasks are built as a
layer over the worker tasks.
I think we should use exactly the same approach for aggregating projects
as well:
- Declare the inter-project dependencies by attaching project artifact
dependencies to configurations, and let these drive the worker task
dependencies. There's no reason why can't allow something like this as a
replacement for dependsOnChildren():
dependencies {
distribution subprojects { configuration = 'runtime' )
}
- Add lifecycle tasks as a layer above the worker task. We would add
pretty much the same lifecycle tasks, such as build, buildDependents,
buildNeeded, etc.
(BTW: What is awkward at the moment. is that we have to overwrite the
root project tasks as we use the groovy-plugin. I haven't gotten
around to get rid of the plugin but will do so soon.)
I'm not saying that this use case is absolutely compelling but it
points to something. We might replace the dependsOn method with an
aggregate method. This aggregate method could define a rule, that
aggregates any task of a project passed as an argument to the
aggregate method. In our case (provided the root project does not uses
the groovy plugin), 'aggregate subprojects' would do what we want
without the necessity to create any aggregator task (with the current
dependsOn method you would still have to create placeholder tasks for
the tasks you want to aggregate).
I think project artifact dependencies + some rules like buildDependents
or buildNeeded or nnnDependents would be a better solution, as they both
model the build better, and reuse concepts we already have.
Adam
---------------------------------------------------------------------
To unsubscribe from this list, please visit:
http://xircles.codehaus.org/manage_email