-
Notifications
You must be signed in to change notification settings - Fork 42
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Requirements of children that are swapped out are not removed, adding "phantom constraints" and breaking resolution #46
Comments
See #45 |
@segiddins, thank you for the pointer. I have tried the fix in #45 and it does not completely resolve the issue - now I get a different conflict, with fewer steps until failure compared to the previous code:
The last one is a phantom dependency, it does not exist in the input data. At a first glance this can be verified by going to https://supermarket.chef.io/cookbooks/sysctl/versions/0.7.0#dependencies |
@segiddins, the problem seems to be that the possibility being swapped out has different requirements from the possibility being swapped in, but those requirement lists are simply combined. If
|
@segiddins, what do you think of the following? This fixes my problem, but I'm not sure if there are unintended side effects. Based on your change #45.
|
I found this chunk of debug code to be very helpful in seeing what's going on:
|
@maxvt can you please make a PR with a test case so we can ensure we don't regress? Thanks! |
diff --git a/lib/molinillo/resolution.rb b/lib/molinillo/resolution.rb
index d92b09d..1120cc7 100644
--- a/lib/molinillo/resolution.rb
+++ b/lib/molinillo/resolution.rb
@@ -356,11 +356,12 @@ module Molinillo
# @return [void]
def fixup_swapped_children(vertex)
payload = vertex.payload
- dep_names = dependencies_for(payload).map(&method(:name_for))
+ deps = dependencies_for(payload).group_by(&method(:name_for))
vertex.outgoing_edges.each do |outgoing_edge|
@parent_of[outgoing_edge.requirement] = states.size - 1
succ = outgoing_edge.destination
- if !dep_names.include?(succ.name) && !succ.root? && succ.predecessors.to_a == [vertex]
+ matching_deps = Array(deps[succ.name])
+ if matching_deps.empty? && !succ.root? && succ.predecessors.to_a == [vertex]
debug(depth) { "Removing orphaned spec #{succ.name} after swapping #{name}" }
succ.requirements.each { |r| @parent_of.delete(r) }
activated.detach_vertex_named(succ.name)
@@ -371,7 +372,10 @@ module Molinillo
requirement_name = name_for(requirement)
(requirement_name == succ.name) || all_successor_names.include?(requirement_name)
end
+ elsif !matching_deps.include?(outgoing_edge.requirement)
+ outgoing_edge.requirement = matching_deps.first
end
+ matching_deps.delete(outgoing_edge.requirement)
end
end
Ought to fix it, but I'm hesitant to commit without a failing test |
@maxvt ping on a failing Molinillo test case for this? |
@segiddins Sorry, it took me a while to find some free time and learn how Molinillo testing works. I modified an existing test case and added a new package with the same name, that scenario looks like it manages to hit this problem. Here's a log with a bunch of debugging output thrown in:
|
Thanks, I'm looking into it now and I think I understand what's going on. No promise when I can figure it out, though |
diff --git a/spec/spec_helper/index.rb b/spec/spec_helper/index.rb
index 9625e9e..16f807e 100644
--- a/spec/spec_helper/index.rb
+++ b/spec/spec_helper/index.rb
@@ -32,6 +32,7 @@ module Molinillo
dependency.satisfied_by?(spec.version)
end
end
+ @search_for[dependency].dup
end
def name_for(dependency) |
Not sure what that change means - was the fixture (TestIndex) bad? Doesn't look like it picks the optimal version of nginx, definitely not what the test expects to happen. What forces it to 0.2.0? |
The test passed with that diff |
I pulled the latest master and the test is still failing for me. I do not know why it passes for you. I tried switching the test index to ordering specified by BundlerIndex -- is the result any different? |
Please merge the PR that I sent to your fork |
Hi, I'm a Berkshelf user facing an issue where a resolution fails due to a constraint that does not actually exist in the solver input. For the background, please see berkshelf/solve#62. The rest is Molinillo-specific investigation.
This is the solver run, you can see that the first version tried is homebrew-2.1.2, and just before performing the swap the payload has a single dependency, build-essential >= 2.1.2:
Ok, step into fixup_swapped_children, we see that the successor (build-essential) is not removed, since other cookbooks depend on it:
After the swap, you can see the new possibility selected has no dependencies:
but the requirement introduced by the possibility that was swapped out is not removed (it was not done in fixup_swapped_children since the successor is not an orphan, and I don't see related logic anywhere else...):
so that (phantom) requirement for build-essential 2.1.2 sticks around, eventually a (real) conflicting requirement is introduced, and resolution fails:
I don't understand the logic of Molinillo enough to understand what's the correct solution. Presumably, requirements that are no longer needed (present in possibility that was swapped out, but absent in the new possibility) need to be removed; but how to find the correct requirements to remove, whether a new state needs to be pushed or rewound as a result of the changing requirements, and so on are unclear to me.
This introduces all kinds of weird behavior up the stack, issues that are resolved by adding version pins, removing pins, all kinds of placebo solutions that do not actually address what seems to be the actual problem at this level. Any help would be greatly appreciated.
The text was updated successfully, but these errors were encountered: