Hi,
What I'm reading below looks exactly like Maven, except for the scope of the
dependencies.
Just for fun, I'll try to make the differences in your system and maven
more concrete. Correct me if I get anything wrong.
In Maven we have 2 types of 'dependencies': artifact dependencies, which
control build order (amongst other things), and 'mojo dependencies', which
hook into the lifecycle and make sure that certain things are executed.
Your system only has 1 type of (build order) dependency, which depends on
phases/goals in all projects in your system. If you were to depend on
the 'install' phase of other projects only, you'd have the Maven <dependency>
thing.
In maven, if you specify a <dependency>, you implicitly specify a dependency
on the install/deploy phase (depending on wheter the artifact's project is in
the reactor). In your system you can specify a dependency on
'generate-resources',
but you can't specify for what project that is. So basically your entire
project tree
can be built using just 1 lifecycle, where for each lifecycle phase, that phase
is executed
for all projects - and all hooks to that phase from all projects are executed.
I bet your system only works for a monolithic project tree, since you require
access to
files in artifacts that have not been completely built. I don't know if you
have a 'deploy'
kind of phase, but is it possible for you to just build a sub-tree of your
project tree,
and if that sub tree requires some icon, can that icon be pulled from a remote
repo?
Snippet:
The key to make this simple was "inversion of dependency". In my project
(module) I don't say "my new phase depends on generate" but "generate
depends on my new phase". When the build tool decides to look at
"generate", it first considers all the phases which "pre-depend" on it.
Like so:
## generate:: generate-includes
This can be done in Maven: in the project that has a 'generate-includes'
requirement
just adds a mojo for that to the 'generate-sources' phase. Other projects don't need to know
about that
Depending projects just know that if they were to depend on a project that has 'generate-sources'
executed, then that project has taken care of generating everything needed for that project.
You don't even have to know it generates includes or icons or whatever.
Now, MetaMake will look for projects which define "generate-includes" (or
new dependencies for it) and runs those phases/goals/targets first.
Basically the same as in maven, though it doesn't search for
'generate-includes', it just
executes 'generate-sources'.
If you were to run 'mvn generate-resources' in a maven project tree you'd get
the same
results as with MetaMake.
The difference here is more of a philosophical nature: in Maven, if you depend
on some
icon resource, you'd specify a dependency on the project that creates it. But
your system
looks like it was meant for C development, and linking there also includes
processing .res files
for GUI elements that embed icons (something like that?). In maven this would
be a bit more complicated,
but there are several solutions for this (which I'm not going to enumerate).
Btw, I've run across a problem that's kind of related to this: i just made a
plugin
that creates a bill of materials from an assembly: it scans the directory
created
by assembly:directory, creates a listing for all files and lists the details for
all jars by looking at the embedded pom.xml in the artifacts.
But that file needs to be inside the assembly itself. So it only works if you
run assembly:directory first. The problem is that you could also run it on some
assembly archive, and then somehow add the file to the assembly afterwards. I
can't just
run it in 'generate-resources' or something since the directory structure
generated from the assembly
needs to be in the file too. Also, updating a tar.gz is not ideal (gunzip, tar
uvf, gzip).
So in this case, I would actually require writing a plugin for the assembly
plugin itself, that
scans the directory just after it's created and just before it's converted to
an archive. But this
is only possible if there's a complete unzipped directory, which isn't the case
if dependencies
are added to the archive directly from the local repository.
So, 2 solutions I can think of:
1) let the assembly plugin support plugins for itself; this is not generic
enough..
2) split the assembly plugin up, binding it to 2 executions, and let the bill
of materials plugin
execute between the 2 executions.
Btw, in your MetaMake system, how would you solve this?
-- Kenney
[EMAIL PROTECTED] wrote:
Jason van Zyl <[EMAIL PROTECTED]> schrieb am 04.12.2006 17:43:29:
As I said before, I've had very good results with a build system in
which
you can specify arbitrary phases and say "this phase depends on
that one".
And how much luck have you had showing that system to other people?
And how much luck have other people had looking at what you've made
without them having to consult you?
It's about as hard to explain and understand as the Maven dependency
system. It's just an odd idea at first glance.
You see, just like Maven, we have several "big" phases ("generate",
"compile", "link", "site").
Eventually, we added generate-includes, generate-source, generate-scripts,
generate-makefiles, ...
The key to make this simple was "inversion of dependency". In my project
(module) I don't say "my new phase depends on generate" but "generate
depends on my new phase". When the build tool decides to look at
"generate", it first considers all the phases which "pre-depend" on it.
Like so:
## generate:: generate-includes
Now, MetaMake will look for projects which define "generate-includes" (or
new dependencies for it) and runs those phases/goals/targets first.
This way, each developer can create their own little world, making sure
all their phases are called in the correct order. You need a second
"generate include" phase? No problem. Hooking them into the big world is
also simple because of the predefined phases which are always there.
The implementation was dead simple (4h in plain C) and worked reliable at
the first attempt. We only had to add caching because searching 20'000
Makefiles for targets was bit slow :-) My project (AROS) is using this
build system for several years, now. Currently, we have roughly 5'000
phases which, oddly enough, makes the build more *simple*.
Let me explain. You have a big maven project with hundreds of modules (we
have about 200). How do you make sure that module X is built and ready
before module Y? Or, say, I need a generated file from a module now but
not all of it? In current Maven, you have to move things around in the
parent POMs. The dependencies "leak".
In our world, I say:
Project X:
## install:: workbench-icon
## workbench-icon:: icon-generator-install
... create the workbench icon ...
Project Y:
## site: workbench-icon
... use the icon ...
Let's imagine I have a clean checkout and want to see the website. Even
though workbench hasn't been completely yet, the single icon file can be
generated after the icon generator has been installed. When I say "mmake
site", it will compile and install the icon generator, generate the
workbench icon and then the HTML files.
In maven, this level of detail is probably not possible. Maven projects
are more encapsulated than ours and I don't think it's even necessary to
go to such lengths in Maven. Operating systems usually have many small
components with heavy dependencies between them, that's why we choose the
approach described above.
What I would like to see is a simple way to "'install' depends on my new
phase/target/goal" in a Mojo and in the execute-elements in the POM. That
way, I could do extra work before something is installed, without
influencing the standard lifecycle, other projects or plugins.
Creating a system
where you have random interaction can potentially create a system
with extremely high infrastructural costs. Shared infrastructure
means lower costs and that means a predictable system.
Random? Since when is the maven dependency resolution "random"? I haven't
seen the code but from what I see, it probebly works exactly like the
MetaMake target resolution.
Regards,
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]