Thanks for all the great feedback on skip proposal: http://www.nabble.com/Some-ideas-on-path-handling-and-our-command-line-td21768085.html
Lately, I've been working another notion: specifying targets via groovy regex on the command line. This could be nice in cases where you don't want to make a bunch of stupid ephemeral targets for ad-hoc target collections (this can be heplful during testing). The regex idea isn't very complicated but I wanted to play with a few different possibilities before asking anybody to look at it in detail. For that reason, instead of talking about target regexes, I'd like to raise an issue that occurred to me along the way: should targets on the command line be treated as "build goals" or as a series "actions" for Gradle to preform? Concretely, should the following commands be equivalent or not? % gradle cow % gradle cow cow cow Gnu Make says: Yes; the second command just redundantly states a goal. Ant says: No; the second command means "execute 'cow' three times". Currently, Gradle does things Ant's way. I believe Gradle should handle it Make's way. At first I thought this subtle distinction really didn't matter all that much, but now I do: I think "build goal" semantics (like Make) are preferable to "build action" semantics (like Ant). Besides being more predictable when it comes to specification via regex, Make's "goal" semantics for targets lead to greater symmetry in terms of Gradle's DAG-oriented design, and scale better in terms of human understanding in cases where the build is complex & tasks aren't idempotent. I'd be very interested in hearing what others think about this issue. Cheers, -Jon -------------------------------------------------------------------- Gory Details: -------------------------------------------------------------------- Suppose task moo dependsOn cow task egg dependsOn cow task cow does not depend on anything If we say: % gradle cow cow cow Currently, in Gradle that means: run the cow task then run the cow task again then run the cow task yet again I believe this should mean "run cow once", and be entirely equivalent to: % gradle cow You could argue either way about the issuance of a warning. Here are the things I think are worth considering: [1] Historical precedent: A mixed bag. Suppose you had the following Makefile: #---------------------------- .PHONY=(cow) cow: echo you said cow #---------------------------- Then suppose you issued the command: % make cow cow cow Gnu make would run cow once. However, suppose you have the following build.xml: <!-- ~~~~~~~~~~~~~~~~~~~~~~~ --> <project default="all"> <target name="cow"> <echo>cow</echo> </target> </project> <!-- ~~~~~~~~~~~~~~~~~~~~~~~ --> Then suppose you issued the command: % ant cow cow cow Ant would run cow three times. Therefore, I think there isn't a particularly strong historical president argument either way. Two commonly-used programs do it differently. [2] Consistency of metaphor When many tasks in a graph depend on cow, cow only gets run once. We don't run cow more than that because our goal was to build it, and once we've done that, we're done. Thus, it seems strange to say that we accept this reasoning when it comes to the DAG, but not when it comes to our command-line specification of what's to be built. This argument seems to lean in favor of the GNU-make's "do it once" semantics. Put differently, GNU Make treats the command line as indicating what your goals are, not like a crippled scripting language. Ant treats the command line as a series of call sites (i.e.: cow() cow() cow()). Build systems are about goals, so the GNU make metaphor seems to be upheld better by "do it once". [3] Symmetry of operations Consider what the following command SHOULD mean: % gradle moo -cow -cow -cow The user has indicated "they don't want cow". Pressing the elevator button over and over should not matter. Ok already, I won't do cow! Therefore, it's currently (and correctly) equivalent to: % gradle moo -cow Let's see what gradle does under harsher conditions. Suppose we've got this build.gradle file: createTask("moo", dependsOn: "fun") {} createTask("cow", dependsOn: "fun") {} createTask("fun") {} Look at what we get right now: % gradle -Dskip.fun moo fun :fun SKIPPED :moo :fun SKIPPED So far so good. We said we didn't want any 'fun' and so our wish was granted. Here's an easy one: % gradle moo :fun :moo Fine, moo dependsOn fun so this is exactly what I'd expect. But now look at this: % gradle moo fun :fun :moo :fun Wait. I'm all for doubling my pleasure, but should I *really* be having this much fun? The 'moo' task already implies the 'fun' task, but here I am running 'fun' twice, probably by accident. If 'fun' was a deeply-nested dependency of the moo task, it's very easy for a person typing on the command line to not realize that. I think you could even say that it's critical for scalability (on the dimension of complexity) that the user should NOT have to know that somewhere deep in the guts of the build that 'moo' eventually calls 'fun'. Hence, explicitly saying 'fun' on the command line should be harmlessly idempotent. The task should only run once. Conclusion: While different from how Ant works, the GNU Make-ish "do it once" semantics seems preferable because it's: o Easier for humans to predict the behavior of complex builds (e.g.: in the case of deep 'fun' task dependencies) o More symmetric with how everybody agrees negated tasks work o more congruent with the goal-oriented nature of a build system (i.e.: command lines should specify goals, not procedures). Just as the DAG spares me from running fun multiple times when more than one thing depends on it, and just like I don't need to keep saying "-Dskip.fun" for each attempt to re-invoke 'fun', I don't think gradle should treat redundant targets in the command line as task invocations. In short, I believe that: % gradle cow cow cow should mean: % gradle cow The fact that it's not working that way now seems like a bug, despite Ant's historical president. Because there are fairly compelling reasons to work GNU Make's way, it's not just a matter of taste. I believe GNU got this one right. What do you think? -Jon --------------------------------------------------------------------- To unsubscribe from this list, please visit: http://xircles.codehaus.org/manage_email