[ 
https://issues.apache.org/jira/browse/IVY-1159?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Ed Burcher updated IVY-1159:
----------------------------

    Description: 
In ResolveEngine.resolve the code that writes the properties file appears to be 
incorrect. 
When the dependencies collection includes two or more entries for the same 
dependency (one from the root ivy file and the others being transitives), the 
properties file will always only ever be populated with the information from 
the IvyNode that belongs to the root ivy file (effectively the comment states 
this, so it certainly appears intentional).

This produces the following bugs / undesirable effects:
 * incorrect delivered descriptor in some situations (where a dependency is 
both directly and transitively imported)
 * order of declaration of dependencies alters behaviour
These are pretty major problems because (as demonstrated below) a 
delivered/published ivy descriptor can identify completely bogus revisions for 
the dynamic->static replacements, which are not to the actual revisions used 
when compiling etc 

Set up
module *one* has no dependencies and has been published (as rev = 1, say)
module *two* has a dependency on module one (only) and has been published (as 
rev = 1, also)
module *three* has dependencies on both modules one and two and *lists them in 
the order two,one*
In the module three descriptor the revisions mentioned for two and one do not 
actually exist (two=0 & one=0 say - repository only contains rev=1 of both)
Ivy settings (attached) has a resolver that refers to a local repo, and has 
force=true and local=true set. 

Problem Case - use case: publishing module 3
1) ivy:resolve on module three, using refresh=true, transitive=true. Otherwise 
nothing special here.
then
2) ivy:deliver (status=reelase, pubdate=now, deliverpattern supplied, 
pubrevision supplied (rev=1))
3) (lastly, the ivy:publish step woud happen here, but is not relevant to the 
problem)

Expected outcome:
Because the primary resolver has force=true, rev 1 of both module dependencies 
of 'three' should be selected [Because rev=1 publications are the only ones 
present in the repository] when resolving three's declared deps (both of which 
declare a dep on rev=0). 

Actual outcome: 
Delivered descriptor correctly names two as being resolved to rev=1. 
Incorrectly names module one as being resolved to rev=0 (which doesn't exist - 
and never has!)

Workaround:
Reverse the order of the declared dependencies in three's ivy descriptor (i.e 
new order is one, two) - problem does not occur.

Diagnosis:
Logs for resolve appear to show everything is fine (the eviction is noted, the 
generated report xml shows the declared direct dependency (one, rev=0) being 
evicted by the transitive dependency (one, rev=1 as declared in two's published 
ivy descriptor)
However, debugging DeliverEngine.java and ResolveEngine.java - it is apparent 
that the 'resolved ivy properties file' is used to drive the replacement of 
dynamic revisions with static ones during deliver. In the error case, the 
properties file shows this:
+revision\:\...@\#\:+0\:\...@\#\:+module\:\...@\#\:+one\:  <snip> :=0 ?
+revision\:\...@\#\:+0\:\...@\#\:+module\:\...@\#\:+two\:   <snip> :=1 release
The '?' is put there because the IvyNode that represented the direct dependency 
has no descriptor (correctly, because it has been evicted). Because the real 
selected revision is not put into the properties file, the ivy:deliver task is 
doomed to produce wrong results.

The correct behaviour in this case would be for the EvictionInfo stored against 
the evicted IvyNode to be inspected to find the appropriate revision 
information. I have attached a pretty ugly example of how this could be 
achieved.

Just before the comment ("The evicted modules have no description, so we can't 
put their status")
{code}
                            if (depDescriptor == null) {
                              EvictionData ed = null;
                              for (int j=0; j<confs.length && ed == null; j++) {
                                ed = dependencies[i].getEvictedData(confs[j]);
                              }
                              if (ed != null) {
                                Collection selected = ed.getSelected();
                                if (selected != null) {
                                  if (selected.size() == 1) {
                                    IvyNode sel = 
(IvyNode)selected.iterator().next();
                                    depDescriptor = sel.getDescriptor();
                                    depResolvedId = sel.getResolvedId();
                                    if (depResolvedId == null) {
                                      throw new 
NullPointerException("getResolvedId() is null for (transitive) " 
                                        + dependencies[i].toString());
                                    }
                                    rev = depResolvedId.getRevision();
                                  }
                                  else if (selected.size() > 1) {
                                    throw new RuntimeException("Unexpectedly 
large number of selecteds within eviction collection");
                                  }
                                }
                              }
                            }
{code}


  was:
In ResolveEngine.resolve the code that writes the properties file appears to be 
incorrect. 
When the dependencies collection includes two or more entries for the same 
dependency (one from the root ivy file and the others being transitives), the 
properties file will always only ever be populated with the information from 
the IvyNode that belongs to the root ivy file (effectively the comment states 
this, so it certainly appears intentional).

This produces the following bugs / undesirable effects:
 * incorrect delivered descriptor in some situations (where a dependency is 
both directly and transitively imported)
 * order of declaration of dependencies alters behaviour
These are pretty major problems because (as demonstrated below) a 
delivered/published ivy descriptor can identify completely bogus revisions for 
the dynamic->static replacements, which are not to the actual revisions used 
when compiling etc 

Set up
module *one* has no dependencies and has been published (as rev = 1, say)
module *two* has a dependency on module one (only) and has been published (as 
rev = 1, also)
module *three* has dependencies on both modules one and two and *lists them in 
the order two,one*
In the module three descriptor the revisions mentioned for two and one do not 
actually exist (two=2 & one=2 say - repository only contains rev=1 of both)
Ivy settings (attached) has a resolver that refers to a local repo, and has 
force=true and local=true set. 

Problem Case - use case: publishing module 3
1) ivy:resolve on module three, using refresh=true, transitive=true. Otherwise 
nothing special here.
then
2) ivy:deliver (status=reelase, pubdate=now, deliverpattern supplied, 
pubrevision supplied (rev=1))
3) (lastly, the ivy:publish step woud happen here, but is not relevant to the 
problem)

Expected outcome:
Because the primary resolver has force=true, rev 1 of both module dependencies 
of 'three' should be selected [Because rev=1 publications are the only ones 
present in the repository] when resolving three's declared deps (both of which 
declare a dep on rev=2). 

Actual outcome: 
Delivered descriptor correctly names two as being resolved to rev=1. 
Incorrectly names module one as being resolved to rev=2 (which doesn't exist - 
and never has!)

Workaround:
Reverse the order of the declared dependencies in three's ivy descriptor (i.e 
new order is one, two) - problem does not occur.

Diagnosis:
Logs for resolve appear to show everything is fine (the eviction is noted, the 
generated report xml shows the declared direct dependency (one, rev=2) being 
evicted by the transitive dependency (one, rev=1 as declared in two's published 
ivy descriptor)
However, debugging DeliverEngine.java and ResolveEngine.java - it is apparent 
that the 'resolved ivy properties file' is used to drive the replacement of 
dynamic revisions with static ones during deliver. In the error case, the 
properties file shows this:
+revision\:\...@\#\:+2\:\...@\#\:+module\:\...@\#\:+one\:  <snip> :=2 ?
+revision\:\...@\#\:+2\:\...@\#\:+module\:\...@\#\:+two\:   <snip> :=1 release
The '?' is put there because the IvyNode that represented the direct dependency 
has no descriptor (correctly, because it has been evicted). Because the real 
selected revision is not put into the properties file, the ivy:deliver task is 
doomed to produce wrong results.

The correct behaviour in this case would be for the EvictionInfo stored against 
the evicted IvyNode to be inspected to find the appropriate revision 
information. I have attached a pretty ugly example of how this could be 
achieved.

Just before the comment ("The evicted modules have no description, so we can't 
put their status")
{code}
                            if (depDescriptor == null) {
                              EvictionData ed = null;
                              for (int j=0; j<confs.length && ed == null; j++) {
                                ed = dependencies[i].getEvictedData(confs[j]);
                              }
                              if (ed != null) {
                                Collection selected = ed.getSelected();
                                if (selected != null) {
                                  if (selected.size() == 1) {
                                    IvyNode sel = 
(IvyNode)selected.iterator().next();
                                    depDescriptor = sel.getDescriptor();
                                    depResolvedId = sel.getResolvedId();
                                    if (depResolvedId == null) {
                                      throw new 
NullPointerException("getResolvedId() is null for (transitive) " 
                                        + dependencies[i].toString());
                                    }
                                    rev = depResolvedId.getRevision();
                                  }
                                  else if (selected.size() > 1) {
                                    throw new RuntimeException("Unexpectedly 
large number of selecteds within eviction collection");
                                  }
                                }
                              }
                            }
{code}



It turns out that things are also sensitive to whether the  (non-existent) 
revision in the root ivy file is lower or higher numerically than the real one. 
This may be because of ordering of the IvyNodes in the dependencies collection. 
I hadn't noticed this when I was simplifying my test case.

=> Replaced refs to rev=2 in the above text to say rev=0. 

> Resolved Ivy Properties written to cache during ivy:resolve incorrectly 
> represents transitive evictions 
> --------------------------------------------------------------------------------------------------------
>
>                 Key: IVY-1159
>                 URL: https://issues.apache.org/jira/browse/IVY-1159
>             Project: Ivy
>          Issue Type: Bug
>          Components: Core
>    Affects Versions: trunk
>            Reporter: Ed Burcher
>
> In ResolveEngine.resolve the code that writes the properties file appears to 
> be incorrect. 
> When the dependencies collection includes two or more entries for the same 
> dependency (one from the root ivy file and the others being transitives), the 
> properties file will always only ever be populated with the information from 
> the IvyNode that belongs to the root ivy file (effectively the comment states 
> this, so it certainly appears intentional).
> This produces the following bugs / undesirable effects:
>  * incorrect delivered descriptor in some situations (where a dependency is 
> both directly and transitively imported)
>  * order of declaration of dependencies alters behaviour
> These are pretty major problems because (as demonstrated below) a 
> delivered/published ivy descriptor can identify completely bogus revisions 
> for the dynamic->static replacements, which are not to the actual revisions 
> used when compiling etc 
> Set up
> module *one* has no dependencies and has been published (as rev = 1, say)
> module *two* has a dependency on module one (only) and has been published (as 
> rev = 1, also)
> module *three* has dependencies on both modules one and two and *lists them 
> in the order two,one*
> In the module three descriptor the revisions mentioned for two and one do not 
> actually exist (two=0 & one=0 say - repository only contains rev=1 of both)
> Ivy settings (attached) has a resolver that refers to a local repo, and has 
> force=true and local=true set. 
> Problem Case - use case: publishing module 3
> 1) ivy:resolve on module three, using refresh=true, transitive=true. 
> Otherwise nothing special here.
> then
> 2) ivy:deliver (status=reelase, pubdate=now, deliverpattern supplied, 
> pubrevision supplied (rev=1))
> 3) (lastly, the ivy:publish step woud happen here, but is not relevant to the 
> problem)
> Expected outcome:
> Because the primary resolver has force=true, rev 1 of both module 
> dependencies of 'three' should be selected [Because rev=1 publications are 
> the only ones present in the repository] when resolving three's declared deps 
> (both of which declare a dep on rev=0). 
> Actual outcome: 
> Delivered descriptor correctly names two as being resolved to rev=1. 
> Incorrectly names module one as being resolved to rev=0 (which doesn't exist 
> - and never has!)
> Workaround:
> Reverse the order of the declared dependencies in three's ivy descriptor (i.e 
> new order is one, two) - problem does not occur.
> Diagnosis:
> Logs for resolve appear to show everything is fine (the eviction is noted, 
> the generated report xml shows the declared direct dependency (one, rev=0) 
> being evicted by the transitive dependency (one, rev=1 as declared in two's 
> published ivy descriptor)
> However, debugging DeliverEngine.java and ResolveEngine.java - it is apparent 
> that the 'resolved ivy properties file' is used to drive the replacement of 
> dynamic revisions with static ones during deliver. In the error case, the 
> properties file shows this:
> +revision\:\...@\#\:+0\:\...@\#\:+module\:\...@\#\:+one\:  <snip> :=0 ?
> +revision\:\...@\#\:+0\:\...@\#\:+module\:\...@\#\:+two\:   <snip> :=1 release
> The '?' is put there because the IvyNode that represented the direct 
> dependency has no descriptor (correctly, because it has been evicted). 
> Because the real selected revision is not put into the properties file, the 
> ivy:deliver task is doomed to produce wrong results.
> The correct behaviour in this case would be for the EvictionInfo stored 
> against the evicted IvyNode to be inspected to find the appropriate revision 
> information. I have attached a pretty ugly example of how this could be 
> achieved.
> Just before the comment ("The evicted modules have no description, so we 
> can't put their status")
> {code}
>                             if (depDescriptor == null) {
>                               EvictionData ed = null;
>                               for (int j=0; j<confs.length && ed == null; 
> j++) {
>                                 ed = dependencies[i].getEvictedData(confs[j]);
>                               }
>                               if (ed != null) {
>                                 Collection selected = ed.getSelected();
>                                 if (selected != null) {
>                                   if (selected.size() == 1) {
>                                     IvyNode sel = 
> (IvyNode)selected.iterator().next();
>                                     depDescriptor = sel.getDescriptor();
>                                     depResolvedId = sel.getResolvedId();
>                                     if (depResolvedId == null) {
>                                       throw new 
> NullPointerException("getResolvedId() is null for (transitive) " 
>                                         + dependencies[i].toString());
>                                     }
>                                     rev = depResolvedId.getRevision();
>                                   }
>                                   else if (selected.size() > 1) {
>                                     throw new RuntimeException("Unexpectedly 
> large number of selecteds within eviction collection");
>                                   }
>                                 }
>                               }
>                             }
> {code}

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.

Reply via email to