Jon Cox wrote:
  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.


I changed this behaviour in the trunk a few days ago, so that Gradle behaves in the Make 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 absolutely agree.

  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



---------------------------------------------------------------------
To unsubscribe from this list, please visit:

   http://xircles.codehaus.org/manage_email


Reply via email to