You are viewing a plain text version of this content. The canonical link for it is here.
Posted to ivy-user@ant.apache.org by Jing Xue <ji...@digizenstudio.com> on 2007/11/19 21:47:47 UTC

conditional resolving


Hi,

I ran into a situation where some dependencies are triggered based on  
how another one is resolved.

Spring 2.5 has reorganized some of the modules. So what was in 2.0's
spring-hibernate3 will be in 2.5's spring-orm, and what was in 2.0's
spring-dao will be in 2.5's spring-tx.  I have a library project that
I'm hoping to support both 2.0 and 2.5 for a while, so I have this in
the ivy.xml:

<dependency org="org.springframework" name="spring-hibernate3"
rev="[2.0, 2.6["  />

which of course will always resolve to the latest 2.0.x because there
is never going to be a 2.5 version for it.  The bigger problem is I
can't find a sane way to specify the replacement, spring-orm, as a
dependency so that the whole thing works with both spring 2.0 and 2.5.

The condition involved here is probably more complex than a version  
switch. It would look something like "use spring-hibernates if  
spring-core is resolved to 2.0, but use spring-orm if spring-core is  
resolved to 2.5."

Any thoughts?
-- 
Jing Xue



Re: conditional resolving

Posted by Xavier Hanin <xa...@gmail.com>.
On Nov 20, 2007 3:57 PM, Jing Xue <ji...@digizenstudio.com> wrote:

>
> Quoting Xavier Hanin <xa...@gmail.com>:
>
> > On Nov 20, 2007 2:04 AM, Jing Xue <ji...@digizenstudio.com> wrote:
> >
> >> This could be interesting. I suppose since a resolver has access to the
> >> current
> >> resolution map, it could at least theoretically make a "stateful"
> >> decision. One potential caveat though is that, IIUC, when two modules
> >> aren't depending on one another, the order of them being resolved is
> >> undefined.
> >
> > It isn't really undefined, the order is always the same, and depends on
> the
> > order of the dependencies defined in your metadata.
>
> True.  On the other hand though, I suspect (by skimming through the
> parsing and resolving code and I _could_ be very wrong) that this
> behavior is like this only because of the way it's implemented. The
> behavior itself is always deterministic, and a rather sane one at
> that, but I don't recall seeing it documented anywhere, which is what
> I meant by "undefined".

I understand, but at least in my mind it's not only the result of the
deterministic implementation, it's really how I think the resolution should
happen. I sometime recommend to put a dependency on the actual revision you
want to finally get at the beginning of the dependencies section, to make
sure eviction of other revisions will happen before actually downloading the
module. So IMO this is more something that should be documented than
undefined :-)

>
>
> > It's very similar to a
> > preorder tree traversal, except that we walk through a graph and that we
> try
> > to avoid visiting evicted nodes. But it's true that it isn't under
> control
> > of the resolver, it's under control of people writing metadata. So it
> may be
> > a problem for you, depending on how well you can control the way
> metadata is
> > written.
> >
> > Resolving the problem without imposing some kind of order is pretty
> > challenging. Maybe this could be done with some modifications in the
> > ResolveEngine, to let a door open just before the end of the resolution
> > process, to let you resolve this dependency only when the rest of the
> graph
> > has been resolved. But the least I can says is that this is not an easy
> > solution.
>
> You mean some sort of "post resolving" extension point which is
> exposed by the resolve engine to handle any dependencies left
> unresolved by the standard algorithm?  That'd be cool.

Yes something like that.


>  I wouldn't
> mind working on it.

That'd be cool :-)


>  It'd probably be way out of scope at the moment,
> though. 8-)

:-)


>
>
> >
> > Another solution I see if you are sure the module making the decision is
> the
> > direct client of your module, is to define a custom parser based on the
> > XmlModuleDescriptorParser we provide, but which "sort" the dependency
> > descriptors returned to make sure your module is always at the end. Then
> in
> > a custom resolver you can make the stateful decision based on the full
> graph
> > of dependencies available at this time. This is not the cleanest thing
> I've
> > ever imagined, but it may work :-)
>
> I think for now we are going to take the easy route - which is to make
> a code branch for spring 2.0 support. Seeing Spring 2.5 just got
> released (only after two RCs, that was quick!) last night, and it's
> supposed to be a drop-in replacement, we might luck out with a rather
> short transition period.
>
> Thanks for the advices. It was a rather interesting discussion even
> from a theoretical standpoint. 8-)

My pleasure.

Xavier

>
>
> Cheers.
> --
> Jing
>
> >
> > Xavier
>
>
>


-- 
Xavier Hanin - Independent Java Consultant
http://xhab.blogspot.com/
http://ant.apache.org/ivy/
http://www.xoocode.org/

Re: conditional resolving

Posted by Jing Xue <ji...@digizenstudio.com>.
Quoting Xavier Hanin <xa...@gmail.com>:

> On Nov 20, 2007 2:04 AM, Jing Xue <ji...@digizenstudio.com> wrote:
>
>> This could be interesting. I suppose since a resolver has access to the
>> current
>> resolution map, it could at least theoretically make a "stateful"
>> decision. One potential caveat though is that, IIUC, when two modules
>> aren't depending on one another, the order of them being resolved is
>> undefined.
>
> It isn't really undefined, the order is always the same, and depends on the
> order of the dependencies defined in your metadata.

True.  On the other hand though, I suspect (by skimming through the  
parsing and resolving code and I _could_ be very wrong) that this  
behavior is like this only because of the way it's implemented. The  
behavior itself is always deterministic, and a rather sane one at  
that, but I don't recall seeing it documented anywhere, which is what  
I meant by "undefined".

> It's very similar to a
> preorder tree traversal, except that we walk through a graph and that we try
> to avoid visiting evicted nodes. But it's true that it isn't under control
> of the resolver, it's under control of people writing metadata. So it may be
> a problem for you, depending on how well you can control the way metadata is
> written.
>
> Resolving the problem without imposing some kind of order is pretty
> challenging. Maybe this could be done with some modifications in the
> ResolveEngine, to let a door open just before the end of the resolution
> process, to let you resolve this dependency only when the rest of the graph
> has been resolved. But the least I can says is that this is not an easy
> solution.

You mean some sort of "post resolving" extension point which is  
exposed by the resolve engine to handle any dependencies left  
unresolved by the standard algorithm?  That'd be cool.  I wouldn't  
mind working on it.  It'd probably be way out of scope at the moment,  
though. 8-)

>
> Another solution I see if you are sure the module making the decision is the
> direct client of your module, is to define a custom parser based on the
> XmlModuleDescriptorParser we provide, but which "sort" the dependency
> descriptors returned to make sure your module is always at the end. Then in
> a custom resolver you can make the stateful decision based on the full graph
> of dependencies available at this time. This is not the cleanest thing I've
> ever imagined, but it may work :-)

I think for now we are going to take the easy route - which is to make  
a code branch for spring 2.0 support. Seeing Spring 2.5 just got  
released (only after two RCs, that was quick!) last night, and it's  
supposed to be a drop-in replacement, we might luck out with a rather  
short transition period.

Thanks for the advices. It was a rather interesting discussion even  
from a theoretical standpoint. 8-)

Cheers.
-- 
Jing

>
> Xavier



Re: conditional resolving

Posted by Xavier Hanin <xa...@gmail.com>.
On Nov 20, 2007 2:04 AM, Jing Xue <ji...@digizenstudio.com> wrote:

> On Mon, Nov 19, 2007 at 10:56:36PM +0100, Xavier Hanin wrote:
> >
> > This use case is very interesting, and a tricky one. I don't see any way
> to
> > express this cleanly and concisely with current Ivy version. You could
> use a
> > custom resolver to handle this very specific logic, but I'm not the sure
> the
> > idea is satisfying.
>
> This could be interesting. I suppose since a resolver has access to the
> current
> resolution map, it could at least theoretically make a "stateful"
> decision. One potential caveat though is that, IIUC, when two modules
> aren't depending on one another, the order of them being resolved is
> undefined.

It isn't really undefined, the order is always the same, and depends on the
order of the dependencies defined in your metadata. It's very similar to a
preorder tree traversal, except that we walk through a graph and that we try
to avoid visiting evicted nodes. But it's true that it isn't under control
of the resolver, it's under control of people writing metadata. So it may be
a problem for you, depending on how well you can control the way metadata is
written.

Resolving the problem without imposing some kind of order is pretty
challenging. Maybe this could be done with some modifications in the
ResolveEngine, to let a door open just before the end of the resolution
process, to let you resolve this dependency only when the rest of the graph
has been resolved. But the least I can says is that this is not an easy
solution.

Another solution I see if you are sure the module making the decision is the
direct client of your module, is to define a custom parser based on the
XmlModuleDescriptorParser we provide, but which "sort" the dependency
descriptors returned to make sure your module is always at the end. Then in
a custom resolver you can make the stateful decision based on the full graph
of dependencies available at this time. This is not the cleanest thing I've
ever imagined, but it may work :-)


> So the custom resolver may be asked to make the decision
> before the relevant data is available.
>
> > Another possible solution is to use two configurations in you module,
> one
> > for spring 2 and one for spring 2.5. Since I don't recommend declaring a
> > dependency on the same module twice with different revisions in the same
> > module (it happens to mostly work, but is not actually supported and
> subject
> > to some bugs), what could be done is define two virtual modules (no
> > publications), one for spring 2, and another for spring 2.5, both having
> > different names. Then you make your module depend on one of them in one
> conf
> > and on the other in the other conf. But then you loose the advantage of
> > conflict resolution for this virtual module at least.
>
> Hmm... I hadn't thought of virtual modules. But as you pointed out, this
> can get complicated, because not only my module depends on these spring
> modules, so do some of the 3rd party tools we use.

So virtual modules is not a solution.

Xavier

>
>
> > All of this depends
> > also on who you would like to take the decision of which version of
> spring
> > to use. Is it a direct client of your module (in which case the
> > configurations solution may be interesting) or a transitive client?
>
> It's most likely a direct client that will make the decision.
>
> Cheers.
> --
> Jing Xue
>
> >
> > Xavier
>



-- 
Xavier Hanin - Independent Java Consultant
http://xhab.blogspot.com/
http://ant.apache.org/ivy/
http://www.xoocode.org/

Re: conditional resolving

Posted by Jing Xue <ji...@digizenstudio.com>.
On Mon, Nov 19, 2007 at 10:56:36PM +0100, Xavier Hanin wrote:
> 
> This use case is very interesting, and a tricky one. I don't see any way to
> express this cleanly and concisely with current Ivy version. You could use a
> custom resolver to handle this very specific logic, but I'm not the sure the
> idea is satisfying.

This could be interesting. I suppose since a resolver has access to the current
resolution map, it could at least theoretically make a "stateful"
decision. One potential caveat though is that, IIUC, when two modules
aren't depending on one another, the order of them being resolved is
undefined. So the custom resolver may be asked to make the decision
before the relevant data is available.

> Another possible solution is to use two configurations in you module, one
> for spring 2 and one for spring 2.5. Since I don't recommend declaring a
> dependency on the same module twice with different revisions in the same
> module (it happens to mostly work, but is not actually supported and subject
> to some bugs), what could be done is define two virtual modules (no
> publications), one for spring 2, and another for spring 2.5, both having
> different names. Then you make your module depend on one of them in one conf
> and on the other in the other conf. But then you loose the advantage of
> conflict resolution for this virtual module at least.

Hmm... I hadn't thought of virtual modules. But as you pointed out, this
can get complicated, because not only my module depends on these spring
modules, so do some of the 3rd party tools we use.

> All of this depends
> also on who you would like to take the decision of which version of spring
> to use. Is it a direct client of your module (in which case the
> configurations solution may be interesting) or a transitive client?

It's most likely a direct client that will make the decision.

Cheers.
-- 
Jing Xue

> 
> Xavier

Re: conditional resolving

Posted by Xavier Hanin <xa...@gmail.com>.
On Nov 19, 2007 9:47 PM, Jing Xue <ji...@digizenstudio.com> wrote:

>
>
> Hi,
>
> I ran into a situation where some dependencies are triggered based on
> how another one is resolved.
>
> Spring 2.5 has reorganized some of the modules. So what was in 2.0's
> spring-hibernate3 will be in 2.5's spring-orm, and what was in 2.0's
> spring-dao will be in 2.5's spring-tx.  I have a library project that
> I'm hoping to support both 2.0 and 2.5 for a while, so I have this in
> the ivy.xml:
>
> <dependency org="org.springframework" name="spring-hibernate3"
> rev="[2.0, 2.6["  />
>
> which of course will always resolve to the latest 2.0.x because there
> is never going to be a 2.5 version for it.  The bigger problem is I
> can't find a sane way to specify the replacement, spring-orm, as a
> dependency so that the whole thing works with both spring 2.0 and 2.5.
>
> The condition involved here is probably more complex than a version
> switch. It would look something like "use spring-hibernates if
> spring-core is resolved to 2.0, but use spring-orm if spring-core is
> resolved to 2.5."
>
> Any thoughts?

This use case is very interesting, and a tricky one. I don't see any way to
express this cleanly and concisely with current Ivy version. You could use a
custom resolver to handle this very specific logic, but I'm not the sure the
idea is satisfying.

Another possible solution is to use two configurations in you module, one
for spring 2 and one for spring 2.5. Since I don't recommend declaring a
dependency on the same module twice with different revisions in the same
module (it happens to mostly work, but is not actually supported and subject
to some bugs), what could be done is define two virtual modules (no
publications), one for spring 2, and another for spring 2.5, both having
different names. Then you make your module depend on one of them in one conf
and on the other in the other conf. But then you loose the advantage of
conflict resolution for this virtual module at least. All of this depends
also on who you would like to take the decision of which version of spring
to use. Is it a direct client of your module (in which case the
configurations solution may be interesting) or a transitive client?

Xavier


>
> --
> Jing Xue
>
>
>


-- 
Xavier Hanin - Independent Java Consultant
http://xhab.blogspot.com/
http://ant.apache.org/ivy/
http://www.xoocode.org/