maven-m2-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Mark H. Wilkinson" <mhw-m2-...@kremvax.net>
Subject Re: #1 thoughts on the goal chain
Date Mon, 10 Jan 2005 14:20:44 GMT
On Thu, 2005-01-06 at 20:57 +1100, Brett Porter wrote:
> Currently, we have the following series of stages when building a JAR:
> 
>                            jar:jar
>                               |
>         +---------------------+-------------------+
>         |                                         |
>         v                                         |
>   surefire:test                                   |
>         |                                         |
>         +------------+------------+----------+    |
>         |            |            |          |    |
>         v            |            |          v    v
> compiler:testCompile |            |    resources:resources
>         |            |            |
>         v            v            v
>        compiler:compile  resources:testResources
> 
> result:
> compiler:compile -> compiler:testCompile -> resources:resources -> resources:testResources
-> surefire:test -> jar:jar
> 
> in stages:
> compile -> resources -> test -> jar
> (this is the plugin chain, not necessarily the particular goals)
> 
> Building a WAR:
> compile -> resources -> test -> war
> 
> Building an artifact as determined by type
> <type> -> build
> eg. jar -> build
> 
> Installing an artifact
> build -> install
> 
> Each goal has its inputs (sources/resources/classes directory) and
> outputs (classes directories/jar).

This seems like as good a time as any to bring up a basic issue that I
have with maven (and ant). I realise that I'm questioning fundamental
principles of the design, but the timing seems right given the current
position of m2's development.

Basically, I'm not convinced that specifying dependencies between
plugins is the right model to use for a build system. It works, sure,
but it leaves plugin developers the job of thinking about the actions of
other plugins as though they are side-effects. I'd argue that it's not
particularly transparent to the end users either: I find it difficult to
work out how to extend the maven build system because I don't have a
good overview of how it fits together. Better documentation would help
here (Brett mentions having plugins create graphs showing their
dependencies further on), but an approach based on concrete and
observable artifacts might be more transparent to everyone.

What I'm thinking of is for m2 to build a dependency graph containing
all the files used in the build process, in a similar way to the
venerable Unix make utility. Recast in this model, each plugin would
declare the set of files that it depends on and the set of files that it
will create, based on the existing information in the pom and the
contents of the file system. m2 would then schedule plugin execution
based on the timestamps of the files in the file system.

I think this would be an improvement because it grounds the build system
on concrete things that are visible to the user (files), rather than the
abstract concept of 'goal'. So, restated as file dependencies, the jar
build might become:

  [dependencies from pom]           [test dependencies from pom]
           |             \                   |
           |              \                  |
           |               \                 |
           v                \                v
  src/main/java/**/*.java    \      src/test/java/**/*.java
           |                  \              |
           | java:compile      \             | java:compile
           |                    ----         |
           v                        \        v
  target/classes/**/*.class ------> target/classes/test-classes/**/*.class
           |               \                 |
           | jar:jar        \                | surefire:test
           |                 -------         |
           v                        \        v
  target/${artifactId}.jar <------- target/surefire-reports/*.txt
           |
           |
           |
           v
        jar:jar

Some immediate advantages: 
      * m2 always does the minimum amount of work possible. Only sources
        that have changed get recompiled, for example. This could be a big
        win for large reactored builds.
      * The user can create any intermediate target. For example, you can
        'm2 target/surefire-reports/org.codehaus.plexus.PlexusTestCaseTest.txt'

I said the timing seemed right to bring this issue up: currently m2
doesn't do any dependency checking to reduce the amount of work that it
does (last time i checked, anyway). I can't imagine this situation will
persist, but the I'm guessing the likely solution will be to add
dependency checking code to the mojos that seem to require it. Surely a
better approach would be to pull this basic behaviour into the m2 core
rather than duplicating it throughout the mojos?

> What if we add, say, antlr? The antlr:antlr goal creates sources for a
> parser definition.
> 
> antlr -> compile -> ...

With file dependencies you'd tackle this by adding this to the dependency
graph:

   src/main/antlr/*
           |
           | antrl:translate
           |
           v
   target/antlr-src/**/*.java
           |
           | java:compile
           |
           v
   target/classes/**/*.class

I'd imagine these additional dependencies being declared by the antlr mojo.

> Should the user should just have to declare "I'm using antlr"?

That's the conclusion I'd come to when thinking about the same problem:
with file dependencies you need some way to work out which plugins get
to add dependencies to the dependency graph. We might have a default
list that covers things like java and site generation, but having some
way to say that non-default plugins should be activated seems like the
sensible thing to do.

An addition is that the user could explicitly force a plugin to be
loaded by referring to one of its targets on the command line. Hence 'm2
antlr:translate jar:jar' would force the antrl plugin to load and its
dependencies to be added to the dependency graph.

> What about a plugin that needs to be in between two existing goals?

This one's more tricky: the swizzle plugin is really overriding the
normal behaviour of the modello plugin. Using file dependencies I can
think of a couple of ways to tackle this: we could have some way to tell
the modello plugin that its generated sources need to placed somewhere
different, and then have the swizzle plugin do its work putting the
result where the modello files would have gone originally. Alternatively
the swizzle plugin could provide its own set of dependencies, but we'd
still need some way to say that the swizzle dependencies should be used
in preference to the modello ones.

These examples highlight the need for the plugins that ship with m2 to
implement a logical and extensible build process. I don't think file-
based dependencies remove the need, but I do think they would make it
easier to make the build process extensible. I've done quite a bit of
thinking about how this could be made to work, and skimmed over some
details here, so please ask questions...

-Mark.


Mime
View raw message