[GRADLE-427] dependsOn doesn't respect dependency order Created: 25/Mar/09 Updated: 01/May/13 Resolved: 01/May/13 |
|
Status: | Resolved |
Project: | Gradle |
Affects Version/s: | 0.5.2 |
Fix Version/s: | 0.7, 1.6-rc-1 |
Type: | Bug | ||
Reporter: | Marc Guillemot | Assignee: | Unassigned |
Resolution: | Fixed | Votes: | 59 |
Attachments: | execution.DefaultTaskGraphExecuter.patch | ||||||||||||||||
Issue Links: |
|
Description |
Using following: createTask("A2", dependsOn: ["C", "B"]) { createTask("B") { println "B" }createTask("C") { println "C" }//----------------------------------------------- gradle A1 and gradle A2 give the same result: which means that the order of the dependencies in the dependsOn list is not respected. |
Comments |
Comment by Marc Guillemot [ 25/Mar/09 ] |
Oops, naturally for gradle A1, the end of the output contains A1 and not A2. |
Comment by Hans Dockter [ 22/Apr/09 ] |
We have to discuss this on the dev list. I will trigger this discussion when we start the work on 0.7. |
Comment by Hans Dockter [ 06/May/09 ] |
I have now run into this issue as well. I have posted something to the dev list. |
Comment by Hans Dockter [ 11/May/09 ] |
Hi Marc, would you tell us the real world problem where you needed those task relationships? |
Comment by Marc Guillemot [ 13/May/09 ] |
I don't remember exactly but it was nearly as simple as in the provided dummy example. I think that I had 2 tasks: compile and copy compiled stuff and I wanted to be able to execute both per default (in the right order) as well as to have the possibility to call each one individually. |
Comment by Hans Dockter [ 11/Jun/09 ] |
We have discussed this on the dev list. The full thread can be found here: http://markmail.org/thread/wn6ifkng6k7os4qn Quote from Adam:
|
Comment by Szczepan Faber [ 12/Dec/09 ] |
Hi guys. I read the conversation on the mailing list (understanding most of it =). Allow me to put my comment here. >Why should task c have anything to say about the relationship between I think I get it though sometime it's just natural... example: clean My real life example is: task 'build-all' (dependsOn: [jar, 'sign-jar', 'build-tiddly', 'zip']) << {} The order matters in my case. The reason I don't have explicit dependencies in some tasks is because it is way easier to work & debug tasks that don't have dependency. Every time I make changes to 'build-tiddly' task I can easily just run this task without triggering its dependency that is just time-consuming. >My second objection is that task ordering is, in practice, almost always Could be. However, not respecting the order feels counter intuitive. I spent some time and I couldn't understand why my build didn't work. I couldn't find it in the docs quickly so I ended up writing tiny gradle script to find out in what order dependencies are processed. dependsOn already offers predictable order (alphabetical, right?) but it's just not intuitive. I think processing dependencies alphabetically is not the right way of coaching build masters how to do proper DAG. I don't want to argue what's the best solution - you guys decide on it. Just wanted you to know my feedback. Keep on doing great stuff with Gradle! |
Comment by Kurt Harriger [ 15/May/10 ] |
I also found this behavior a bit unexpected. IMHO, the dependency graph should be processed using an in-order traversal with the additional restriction that each nodes are executed only once. |
Comment by Hans Dockter [ 07/Jun/10 ] |
@Kurt We see that there is a problem to solve that is not solved well yet by Gradle. We don't think that dependency order is a good solution, as pointed out. We want to address this issue in 1.0. But I see your point re the reordering and why to do it at all. Could you raise this issue on the dev list? |
Comment by Hans Dockter [ 15/Aug/10 ] |
I reopen this issue as it represents a problem still to be solved, although we want to solve it in a different ways then proposed. |
Comment by Jakub Trojanek [ 07/Sep/10 ] |
Just my two cents: I was enthusiastic about gradle until I hit this issue. This basically prevents transitional migration of our project, as I cannot import most of our ant targets due to their reliance on ordered "depends" list. So I would have been stuck with rewriting all ant targets. Another real life example: task release(dependsOn: ["getVersion", "releaseLogic", "sendMail"] { |
Comment by Hans Dockter [ 28/Sep/10 ] |
Hi Jakub, thanks a lot for your feedback. You are right, the ant migration aspect is another important thing to consider. We will solve this is in one way or the other. |
Comment by Mark Smith [ 22/Sep/11 ] |
Hi guys, I was just wondering if there was any more progress on this. I found this issue after encountering a similar problem to Jakub while trying to set our Gradle project. Our use case is that we want to let our developers just run the war task for their grails app, but when we want to actually upload the war to our nexus server, we'd like to run clean before the war task. The most natural way to do this seemed to be having no dependsOn specified for the war task, but then have ["clean", "war"] for the dependsOn for the upload task, but from this discussion I see that that's not correct or reliable. We're currently on 1.0 M3 and I was wondering if this is still going to be addressed for 1.0, as per the comment from Hans on June 7th. Thanks, Mark |
Comment by Adam Murdoch [ 22/Sep/11 ] |
@mark: We want to solve the 'clean must run first' use case. We're yet to decide exactly what is in or out for 1.0 release, but I'd like to include it if we can. However, we're very unlikely to solve the use case by changing Task.dependsOn to imply any ordering between the dependencies. Perhaps you could raise a separate jira issue for your particular use case, so we can tackle it separately. |
Comment by Szczepan Faber [ 24/Sep/11 ] |
>However, we're very unlikely to solve the use case by changing Task.dependsOn to imply Too bad Albeit controversial, I find it the most natural thing to do It even feels consistent with our current approach to task names given via the start parameters - task names hint at order but ultimately it's the dependsOn on that is the master information for the DAG. Anyways, I'm eager to see how we approach that issue |
Comment by Blaine Simpson [ 06/Oct/11 ] |
IMO the objections about implications to graph maintenance aren't justified. A preferred sequence would be just an additional constraint on the DAG. It's like saying that color-coding DAG nodes to indicate some aspect would harm its authenticity. As a matter of fact, the graph nodes already have a sequence, and it is the alphabetical ordering of the Task names, so we just want to apply a different ordering. In the real world we have practical needs, and the graph structures need to accommodate them. Even if DAG could not manage dependency execution sequence in a natural way, that would indicate that DAG is inadequate for a build system, not a need to preserve the structure by hacking weak and limited work-arounds (like command line switches to force a specific task to run first). Just like I experienced with a different project a year ago, after championing conversion to Gradle and finally getting approval for the HyperSQL project I have to withdraw my recommendation due the embarrassing inability to control dependency sequencing in a manageable way like we have done easily and intuitively with Ant for 10 years. |
Comment by Kurt Harriger [ 06/Oct/11 ] |
I think I worked around the issue with something like this: I added bit of sugar adding to list then adding logic to each task automagically. |
Comment by Blaine Simpson [ 08/Oct/11 ] |
I just completed my work-around to preserve Ant build file dependency precedence specifications. Here you are: There is some unrelated stuff in there. The methods and functions of interest here are
My 'tasks' override makes up in large part for the lack of a private task mechanism to hide tasks similarly to Ant non-described and -* tasks. My system supports nested Ant imports, but you must specify all file names (as you can see I have done). Would be easy to pull in the imported file names automatically, but I though it best to leave that decision up to the invoker. Checks are made for dependency cycles, where in one dependency spec we have A... B and in another B... A. Doesn't handle this, but my highly-nested 74-target Ant build file doesn't have any, so you probably won't either. Unrelated to the dependency sequencing, but of interest to others wrapping Ant, I use the custom closure and the resequence.destDir option to work around Gradle's multiple terrible bugs that prevent the basedir specified in the Ant build file from working. |
Comment by Szczepan Faber [ 14/Oct/11 ] |
@Kurt, execute() method only executes 'actions' attached to the task via doFirst() / doLast(). So your workaround may not work for all kinds tasks. For example, most built-in tasks/custom tasks don't have any doFirst/doLast actions by default. |
Comment by Daniel Plappert [ 10/Nov/11 ] |
It is very important to set the order in which tasks should be executed. I came across this bug while I was creating a task for testing our web-app. Before webtests can be executed, the schema has to be created, the jetty must be configured and so on: task createSchema << {} In this case, the order of execution is very important, i.e. the task dropSchema is executed before createSchema, which is currently impossible. And I prefer not to change the task createSchema by adding a dependOn dropShema. This would be just a workaround. Also in some scenarios I don't want to drop the schema before creating one, because in this way some other tasks will cause problems. There are many scenarios in which the order is important and has to be set by dependsOn. Currently we have to create a workaround to solve this issue, but it would be very nice, if this "bug" is fixed in one of the next versions. |
Comment by Scott Stewart [ 14/Nov/11 ] |
Wanted to add my sentiment, like others, this may prevent us from moving to Gradle. We have a large, complex, existing ant build that is highly dependent on the tasks being executed in order of dependency declaration. Requirement #1 for any build changes is the ability to do it incrementally. I don't even know how anyone can say in good-faith that Gradle supports existing Ant builds when it doesn't respect the order of dependency declaration. I've seen dozens of Ant scripts and the reliance of this ordering is everywhere. Certainly the dependent tasks need to be executed in some order. Is the arbitrary choice of alphabetical order provide any benefit whatsoever? |
Comment by Krystian Szczęsny [ 01/Dec/11 ] |
Was there any progress on this issue? I read Adam comment on the mailing list and I can't imagine how he came up with it. I guess view really depends on what you want to use gradle for. For his question:
I'm not sure what Adam means by this list, but I assume it's a list of tasks ran by the user. If so [for me] it's quite simple, you run task a, then you run task b, then you run task c [since b and a were already ran], then you run task d [since a and c were already ran] and finally you run task e [since c and d were already done]. If it's just a definition of tasks and user decides to run d and e, then you run a, c, d, e. I think you want to add some intelligence to gradle, which is not required. Let users decide what to run and in what order. If something was ran then don't do it again [or allow user to specify dependencies which have to be re-run even if they were already]. task a task b task c task d(dependsOn: a, b) task e(dependsOn: d, c) and they want to run task e without running a, what would you tell them? Just rewrite the tasks. Currently, I've got tasks like: checkout from VS clean build package(dependsOn: clean, build) stop server do some cleanup on server copy package to server start server So I have all this little tasks, with their dependencies and in the end I wanted to have a deploy task: deploy(dependsOn: git, war, stop, cleanup, copy, start) I was pretty shocked, when I saw gradle reordering all the tasks and trying to execute: cleanup copy git start stop war I understand that what is going on behind the scenes is complex and there are things about gradle I have no clue about, but in the end it should be me who decides the order of things. |
Comment by Andres Almiray [ 12/Dec/11 ] |
If I could give this issue more votes I would. |
Comment by Christian Mouttet [ 11/Jan/12 ] |
I did some debugging and found a wrong usage of TreeSet<Task>. org.gradle.api.DefaultTask.Task is a Comparator that sorts alphabetically by its path. Just changing it to a List and reverse its original order helps a lot. The attached patch is based on branch REL_1.0-milestone-7. |
Comment by Paul Jimenez [ 17/Feb/12 ] |
IMO, this is NOT a bug, though it does point up a deficiency in Gradle. Dependency order should not be respected; doing so breaks Gradle the same way ant is broken, and keeps it from being able to (in the future) do parallel builds. Instead, Gradle needs a facility to easily invoke one task from another, procedurally. Saying that 'a depends on b and c' says nothing about the order of b and c. Saying 'a needs to do first b, then c' does, and Gradle needs to be able to express both. task a(dependsOn: [b, c]) but the second could be either: task a { b.execute() c.execute() } or: task a(dependsOn: b) { c.execute() } ...though I'm enough of a noob to not know if there's actually an 'execute()' method on each task (or what it's actually called if it does exist). |
Comment by Tom Widmer [ 28/Feb/12 ] |
I think at heart this is about the ability to specify that: You could have something like Task.orderAfter to specify this. This method wouldn't imply a dependency, just that if both tasks are scheduled, one should happen after the other. I guess you end up with two DAGs - one for dependencies, and one for explicit ordering (which will usually be small). The commandline list of tasks could also add edges to the ordering DAG (e.g. a commandline of "clean build" will implicitly call "build.orderAfter clean"). Merging the two might be as easy as this: for each edge in the ordering DAG, if the two ends are in the dependency DAG, add the edge in from the ordering one into the dependency one (it's probably harder though!). In my case, I just want to get a continuous integration build to do things in the right order. My workaround is: def whenScheduled(task, closure) { if (gradle.startParameter.taskNames.contains(task)) { closure(task) } } task cibuild { project.buildType = 'build' dependsOn 'clean', 'test', 'artifactoryPublish' whenScheduled(name) { gradle.projectsEvaluated { project.artifactoryPublish.dependsOn 'test' project.compileJava.dependsOn 'clean' } } } which is pretty much applying a limited version of the DAG merging manually! |
Comment by Phil DeJarnett [ 28/Feb/12 ] |
@Tom Widmer I think the way you are hacking a solution leads to a possible fix that doesn't require a second DAG: Add a command that says, effectively, dependsOnIfActive(task) This would allow the current DAG to order the events, but if the task is not requested explicitly or implicitly, it's not included in the tree. I don't know if this would work for every case, but it might be a good enough compromise. It also doesn't require any explicit task ordering. |
Comment by Connor Garvey [ 21/Jun/12 ] |
Paul's solution is the simplest. The semantics of dependsOn aren't correct for the situations most people are describing. A CI build doesn't depend on other tasks to be done. It is those tasks. Allowing tasks to directly execute other tasks is straightforward and logical and doesn't force developers to learn a new language. In my case, I have a build in which I want to ... try { startServer; integrationTest } finally { stopServer } I want to just do that. |
Comment by wujek srujek [ 14/Jul/12 ] |
Hi. My 2cent maybe: I have the use case: to do what I want. To my surprise, this is completely ignored! I think this is utterly inconsistent with the fact that when I specify the tasks on the command line, their ordering is taken into account, unless it is inconsistent with the task DAG. So when I do: |
Comment by Trevor Samaroo [ 02/Aug/12 ] |
Instead of defaulting to the user defined order in dependsOn, you default to ordering based on the alphabet. You think this is better? you could just as easily default to a DAG influenced by the dependsOn definition (user defined ordering) instead of influencing the DAG with an alphabetic sort routine - no? Maybe make it a property of gradle ... gradle.taskDependencyMode=Alphabet vs User Defined. Its scary to think of what happens to builds when you simply rename a task and the poor developer running the build isn't a gradle expert. As an example - the third dependency here only runs third (before doTag) because i *changed its task name* from "doVersion" to "doSVersion". task checkOutVersionAndTag(dependsOn: ['checkout','doSnapshotCheck', 'doSVersion', 'doTag']) << {} sometimes you want to run a task before another one, and at other times you don't. you want to have some say in ordering tasks. i don't want doTag to depend on doVersion because i don't need to version all the time i call doTag. and its a huge hack to name tasks in such a way that they execute when you want them. i don't see any clean way to do something so simple. We're just users of this build system and i think we just want this as a feature. I wish Gradle would be more practical about this issue - its supposed to solve frustrations with other build systems, but has seemingly illogical limitations (reminds me of not being able pass in a maven pom version into a maven build.) |
Comment by Mauro Molinari [ 03/Aug/12 ] |
I'm voting for this bug, not because I want dependsOn to necessarily respect the order of the specified tasks (once it is well documented), but because I need a way to solve my problem. This is my use case. I have a task that generated Java files from XSDs. The translation XSD->Java is not done at build time, but only on-demand when needed (i.e.: when the XSDs change and at development time a new Java src generation is needed). So, my compile task, that compiles those generated Java files for building, must not depend on the Java source generation.
I then discovered that dependsOn(A, B) does not guarantee that A is executed before B. No problem for me, but I can't find a proper way to express this. Just my contribution. Any suggestion is welcome. |
Comment by Carus Kyle [ 21/Aug/12 ] |
My two cents.. task install_all_the_things(type:Workflow) { // task list here, maybe a few options? // could even facilitate progress bar functionality? } each task can still have its dependsOn: field for what it really depends on, not just to force an order. This would allow you to call individual tasks when needed without triggering a whole huge chain and still call the whole chain for defined workflow. |
Comment by Adam Murdoch [ 22/Aug/12 ] |
@Carus Kyle, this is more or less what we're looking at doing. |
Comment by Daniel Gredler [ 24/Aug/12 ] |
I'm a little bit hesitant to play devil's advocate when the consensus seems to be that dependency ordering is a bad idea, but here goes! Regarding Adam's objection that respecting task dependency order degenerates the task DAG into some sort of "DAG+", I would say this is true. However, is it better to have a single "DAG+" task model, or is it better to split it into a pure "DAG" model augmented with a separate "+" model which contains the ordering information? I understand that a pure DAG is very attractive, but we're agreed that it can't fully express the user's intent in all scenarios. At this point the question seems to be whether the extra information is added to the primary task graph model or delegated to a secondary "workflow task" model that enriches the primary model. I would be especially concerned if we end up with a declarative "DAG" model and a procedural "+" model. It is worth mentioning that many commonly-used tools in the Java world have addressed variants of this problem: Ant [1], which respects order (I'd be very interested to learn more about how "ant is broken" because of this, as Paul says above); TestNG, which does not respect order on test dependencies [2], but does provide some support for test ordering [3]; Spring, which I believe does implicitly respect bean dependency order [4]. Regarding Adam's objection that a "DAG+" is lossy and doesn't fully express the rationale for the ordering, I'm having trouble conceiving of a solution that meets that goal in a better way. If someone (e.g. Daniel Plappert above) wants to create a "runWebTests" task that depends on "dropSchema", "createSchema", and "startJetty" (in that order), then I can't think of a solution that more clearly or succinctly expresses that in this context "createSchema" comes before "startJetty", but "startJetty" is also intended to be run independently sometimes. We should also consider the principle of least surprise. Gradle is a Groovy DSL, and in keeping with idiomatic Groovy, users will intuitively expect that [a, b, c] will be an ordered list and used as such. It would be convenient if Groovy had a better notation for unordered sets, and then the behavior of the dependency collection could vary according to the collection type (ordered or not). Unfortunately, the easiest collection shorthand is for a list, meaning that most people would use lists by default, and then almost nobody would be able to benefit from e.g. build parallelization further down the road. Maybe a new workflow task is the best solution... but would it be limited to use as an "entry point" task, or would other tasks be able to depend on workflow tasks? If limited to use as an "entry point" task, it would probably limit the impact of having this separate "+" model, but I'm not sure it would cover all use cases. If not limited to use as an "entry point" task, why not just keep it all in a single unified "DAG+" model? Either way, you seem to end up extending the model in a way that muddles the task DAG. Finally, an off-the-wall idea: I know you can do operator overloading in Groovy, although I've never had to do it myself. You could probably make the following DSL express ordering, while keeping the current default unordered behavior: task runWebTests (dependsOn: dropSchema >> createSchema >> startJetty) // all ordered task runWebTests (dependsOn: [dropSchema >> createSchema >> startJetty]) // all ordered task runWebTests (dependsOn: dropSchema >>> createSchema >>> startJetty) // all ordered (use unsigned right shift instead of right shift?) task runWebTests (dependsOn: dropSchema >> createSchema >> [startJetty, startFtpServer]) // all ordered, except Jetty and FTP can be started in parallel task runWebTests (dependsOn: [dropSchema, createSchema, startJetty]) // no guaranteed order, like now Sorry for the wall of text... thanks for reading! [1] http://ant.apache.org/manual/targets.html |
Comment by wujek srujek [ 24/Aug/12 ] |
Not having thought about it much, I must say the above examples (dropSchema >> createSchema >> [startJetty, startFtpServer]) look very appealing and are really expressive in my opinion. |
Comment by Ryan Shillington [ 28/Aug/12 ] |
Yes, +1. I agree with Daniel Gredler's answer above as well, although modifying the default behavior to execute dependencies in order is what I would do personally. Put it in the change notes for v2 and be done with it. As a long time lurker, I signed up for an account just to vote for this. I saw this issue when I was using milestone-6 and left it because, well, surely it'll get solved. It's such an obvious feature request and such super important functionality. I'm surprised that the Gradle community has allowed this to fester for so long. A good Gradle best practice is to never write a task that depends on the alphabetical ordering. You know that's going to burn you when somebody modifies the name of a task. It's just bad coding practice. We use .execute() instead, which I know, is also bad. It won't burn us without upgrading Gradle though. |
Comment by Adam Murdoch [ 03/Sep/12 ] |
@Daniel, good points. There are a few things I want to comment on. The workflow step (or build type as we're calling it) is intended to be a starting point, not the final destination. It's easy to implement, solves maybe 70% of the use cases we've seen, and allows us to drive work on a richer task execution model that can later become public. The build types are not just about task ordering - they're declarative elements that describe the public entry points of the build, the inputs that they take (eg when I'm doing a release build, I need to provide credentials for the repository), and the conditional logic that has to happen for that build (eg when I'm doing a CI build, wire in the test coverage report). There's a lot of value in build types even if they don't solve everyone's task ordering problems. But they are a step towards a more general solution. The plan is certainly not to end up with separate declarative DAG and imperative + pieces. Instead, we will have a high level declarative model that describes what you want to build, and a low level declarative model of how that should happen. The high level model is used to assemble the low level model. They both describe the same thing, just with different views: The high level model is a graph of things that depend on each other, and the low level model is a graph of actions (tasks) to be executed to achieve the result. We already have this layering: when you declare a project dependency, you're not saying anything about which tasks to run. You're just stating: 'my library foo depends on library bar, please make sure it's available before attempting to compile foo'. From this high level declaration, the low level task dependencies are wired in. And so with the canonical 'start jetty then run my tests' use case. There is a hard dependency here: my tests need my web app to be running. This this isn't a task dependency. The tests don't care how the web app was deployed. It's a dependency between things: my web app and my tests. So, in the high-level model, you'd state 'my tests need my web app to be running', and Gradle would turn that into the appropriate low level task dependencies. The jetty plugin, for example, might declare 'I know how to deploy a web app' and Gradle can ask it to do so. Adding in the database schema, we see the same thing. There is a hard dependency here: my web app needs a database instance to be running with my schema. Again, it's not a task dependency, it's a dependency between things: my web app and the database instance. In the high level model you'd state: my web app needs a database instance with my schema, and Gradle would turn that into the appropriate low level task dependencies. Maybe the mysql plugins declares 'I know how to create a database instance' and the liquibase plugin declares 'I know how to apply a schema to a database instance', and Gradle can ask them to do so. Why is this useful? Firstly, by declaring the dependencies at the right level of abstraction, you keep things simple. There's no need for dependency ordering or any of that. It's also declaring the actual dependencies, not the dependencies denormalised into a set of tasks. Secondly, you keep things flexible. Gradle can choose the appropriate tasks based on the current state of the world: If there's already a database instance with the schema applied, then just delete all the rows and reapply the test data. If there's database instance with the wrong schema, then drop all the tables and apply the schema. If there's no database instance, create it and apply the schema and test data. If the tests are going to be run in parallel, then spin up a separate database instance for each test worker. If I'm doing a developer build, reuse the instance I have on my local machine. If I'm doing a CI build, then rebuild the database instance from scratch in the QA environment. So, we have a nice high level description of the relationships between the software components. Ideally, you work only at this level and never touch the task model. However, there will still be cases where you need to work with the task model, for whatever reason. This will still be a graph, but with several different types of edges, or relationships. There will be no orderings between the edges. Currently, we're looking at the following relationships:
There will be some conveniences for the above. Maybe even your proposed syntax, so that: task a(dependsOn: b >> c) is shorthand for: tasks (b,c) must run before task a, and when task a is scheduled then task b and all it dependencies must run before task c and all its dependencies. |
Comment by Attila Kelemen [ 04/Sep/12 ] |
I'm not sure if I should open a separate issue or not but my RFE could probably offer a solution to this problem. I also sometimes needed to execute tasks in an order but cannot declare a depends on relationship on them (like with the rebuild task). What I was really looking for when doing this is an aggregator task. That is, to me specifying an order between edges of the graph seems completely counter intuitive. But adding a method to Project to create an aggregated task from multiple tasks seems to be the way to go. For example:
Here rebuild is an instance of org.gradle.api.Task. |
Comment by Bretislav Wajtr [ 02/Oct/12 ] |
+1 for resolving the bug, because of this problem, gradle is a no-go for us and we have to stick with Ant for the time being Ugly workaround I came with (showing that user-defined task order really has meaning). task xbuild(dependsOn: build) (== gradle internally sorts dependencies alphabetically, so "renaming" build task to xbuild solves the problem and the clean task is performed before build task this way) I have desired functionality, but... |
Comment by Taylor Brown [ 10/Jan/13 ] |
I too was surprised to see that this didn't work. I previously had a set of tasks defined on the command line, and of course task ordering was respected there. When I decided to move this set of ordered tasks into a single task, I had not way of doing it. My "Build" task does not "depend on" my "clean" task. But if I'm cleaning AND building, I sure as heck want my build to come after clean. I look forward to this being solved. Thanks! |
Comment by M. Chelfi [ 07/Feb/13 ] |
I have a naive suggestion, why not use a List<Task> in the dependsOn instead of a Set<Task>? this would ensure iteration order an honor the task order. |
Comment by Paul Jimenez [ 07/Feb/13 ] |
Switching behavior on whether the parameter was a List or a Set might be an okay compromise. It's a bit subtle, but as long as it's documented it would allow both desired behaviors. Note that it uses the 'expected' (ordered) behavior more easily since it's a little easier to construct a List than a Set in Groovy. Consider: task a(dependsOn: [b, c]) would mean execute b, then c, then a, but task a(dependsOn: ([b, c] as Set)) would mean execute b and c in any order, and then a. Sounds like a good solution to me! Who's up for implementation? Something like: if (dependsOn instanceOf Set) { // existing behavior } else if (dependsOn instanceOf List) { // iterate over the list of tasks } |
Comment by Matias Bjarland [ 07/Feb/13 ] |
For the two last posts: I'm fairly certain this issue is not a question of how to implement an ordered dependency notation. The question is philosophical, not technical: should the dependency graph be ordered or not? There are (as per previous comments above) benefits to an unordered set and reasons for keeping the default and large majority or dependecy declarations unordered. Last I heard gradleware was leaning towards an extra notation (i.e. not replacing the old one but creating an additional one) for the potential ordered dependency list. |
Comment by M. Chelfi [ 07/Feb/13 ] |
Matias, I did read the previous posts and I agree with you it's a philosophical view on the question. I do not exactly know how the internals of gradle would handle the implication of looking at the dependsOn as ordered but having the impression that at some point it decides to iterate through the dependent tasks I thought replacing the underlying Set structure with List would do the trick without compromising the DAG, that is why also I started my post by saying a naive suggestion. |
Comment by Paul Jimenez [ 07/Feb/13 ] |
@Matias: actually, the question is how to implement an ordered dependency notation. It's fairly well agreed that the current bug title "dependsOn doesn't respect dependency order" isn't the real bug. The real bug is that there's currently not a good way to notate ordered dependencies. It's not the philosophical question of "should the graph be ordered or not" because the dependency graph is ordered, there's just not an easy way to express this additionally desired ordering (intermediate 'throwaway' tasks would do it, but that's not easy.) I put up one strawman solution last February, M. Chelfi's suggestion for said syntax is as valid as the other proposals. |
Comment by Adam Murdoch [ 10/Feb/13 ] |
For those who are interested, there has been some recent discussion of this on the dev mailing list, in this thread: http://gradle.1045684.n5.nabble.com/Gradle-reporting-improvements-tt5710408.html The relevant stuff is a little way into the thread, starting at: http://gradle.1045684.n5.nabble.com/Gradle-reporting-improvements-tp5710408p5710802.html Everyone is welcome to join in the discussion there. |
Comment by Nathan Wells [ 25/Mar/13 ] |
See |
Comment by Adam Murdoch [ 01/May/13 ] |
Gradle 1.6 adds support for task ordering rules, which solve many of the use cases listed in this issue. We're not finished with task ordering and we haven't yet solved all the use cases here, but I've marked this issue as 'fixed'. If you find problems or want to suggest improvements for task ordering and execution, please feel free to raise new issues via the forums. Please note that we're very unlikely to change dependsOn to run tasks in the order listed, as requested in the title of this issue. |