Commit e473d2ae by Sébastien Eustace

Fix conflict resolution in mixology

parent f75b1cb7
......@@ -84,7 +84,9 @@ class DependencyGraph:
dot_edges = []
for n, v in self.vertices.items():
dot_vertices.append(' {} [label="{}|{}"]'.format(n, n, v.payload))
dot_vertices.append(
' {} [label="{}|{}"]'.format(n, n, v.payload or '')
)
for e in v.outgoing_edges:
label = e.requirement
dot_edges.append(
......
......@@ -37,7 +37,7 @@ class AddEdgeNoCircular(Action):
def down(self, graph):
edge = self.make_edge(graph)
self._delete_first(edge.origin.outgoing_edges, edge)
self._delete_first(edge.origin.incoming_edges, edge)
self._delete_first(edge.destination.incoming_edges, edge)
def make_edge(self, graph):
return Edge(
......@@ -55,5 +55,4 @@ class AddEdgeNoCircular(Action):
except ValueError:
return
if index != -1:
elements.pop(index)
del elements[index]
......@@ -55,5 +55,4 @@ class DeleteEdge(Action):
except ValueError:
return
if index != -1:
elements.pop(index)
del elements[index]
......@@ -21,6 +21,8 @@ class DetachVertexNamed(Action):
if self._name not in graph.vertices:
return []
print('Detaching', graph.vertices[self._name])
self._vertex = graph.vertices[self._name]
del graph.vertices[self._name]
removed_vertices = [self._vertex]
......
......@@ -20,6 +20,9 @@ class Edge:
def requirement(self):
return self._requirement
def __eq__(self, other):
return self._origin == other.origin and self._destination == other.destination
def __repr__(self):
return '<Edge {} -> {}>'.format(
self._origin.name, self._destination.name
......
from ..utils import unique
class Vertex:
def __init__(self, name, payload):
......@@ -14,9 +16,9 @@ class Vertex:
@property
def requirements(self):
return [
return unique([
edge.requirement for edge in self.incoming_edges
] + self._explicit_requirements
] + self._explicit_requirements)
@property
def predecessors(self):
......@@ -92,4 +94,4 @@ class Vertex:
return other.path_to(self)
def __repr__(self):
return '<Vertex {}>'.format(self.name)
return '<Vertex {} ({})>'.format(self.name, self.payload)
......@@ -10,7 +10,7 @@ class PossibilitySet:
return self.possibilities[-1]
def __str__(self):
return '[{}]'.format(', '.join([repr(p) for p in self.possibilities]))
return '[{}]'.format(', '.join([str(p) for p in self.possibilities]))
def __repr__(self):
return f'<PossibilitySet {str(self)}>'
......@@ -99,15 +99,15 @@ class Resolution:
"""
self._started_at = datetime.now()
self._handle_missing_or_push_dependency_state(self._initial_state())
self._debug(
f'Starting resolution ({self._started_at})\n'
f'Requested dependencies: {self._original_requested}'
f'Requested dependencies: '
f'{[str(d) for d in self._original_requested]}'
)
self._ui.before_resolution()
self._handle_missing_or_push_dependency_state(self._initial_state())
def _resolve_activated_specs(self) -> DependencyGraph:
for vertex in self.activated.vertices.values():
if not vertex.payload:
......@@ -235,16 +235,14 @@ class Resolution:
conflicts = self.state.conflicts
sliced_states = self._states[details_for_unwind.state_index + 1:]
if details_for_unwind.state_index == -1:
self._states = []
else:
self._states = self._states[:details_for_unwind.state_index]
self._states = self._states[:details_for_unwind.state_index + 1]
self._raise_error_unless_state(conflicts)
if sliced_states:
self.activated.rewind_to(
sliced_states[0] or 'initial_state'
)
self.state.conflicts = conflicts
self.state.unused_unwind_options = unwind_options
self._filter_possibilities_after_unwind(details_for_unwind)
......@@ -367,10 +365,11 @@ class Resolution:
parent_r = self._parent_of(r)
if parent_r is None:
continue
partial_tree.insert(0, parent_r)
requirement_state = self._find_state_for(parent_r)
possibilities = [
r in set_.dependencies
r.name in map(lambda x: x.name, set_.dependencies)
for set_ in requirement_state.possibilities
]
if any(possibilities):
......@@ -393,7 +392,7 @@ class Resolution:
partial_tree.insert(0, grandparent_r)
requirement_state = self._find_state_for(grandparent_r)
possibilities = [
parent_r in set_.dependencies
parent_r.name in map(lambda x: x.name, set_.dependencies)
for set_ in requirement_state.possibilities
]
if any(possibilities):
......@@ -514,7 +513,9 @@ class Resolution:
unwinds_to_state.append(unwind_details)
primary_unwinds = unique([
uw for uw in unwinds_to_state if uw.unwinding_to_primary_requirement
uw
for uw in unwinds_to_state
if uw.unwinding_to_primary_requirement()
])
parent_unwinds = unique(unwinds_to_state)
parent_unwinds = [uw for uw in parent_unwinds if uw not in primary_unwinds]
......@@ -530,10 +531,10 @@ class Resolution:
]):
allowed_possibility_sets.append(possibility_set)
requirements_to_avoid = flat_map(
requirements_to_avoid = list(flat_map(
parent_unwinds,
lambda x: x.sub_dependencies_to_avoid
)
))
possibilities = []
for possibility_set in self.state.possibilities:
......@@ -637,12 +638,14 @@ class Resolution:
if not self._parents_of[requirement]:
return
index = self._parents_of[requirement][-1]
if not index:
try:
index = self._parents_of[requirement][-1]
except ValueError:
return
parent_state = self._states[index]
if not parent_state:
try:
parent_state = self._states[index]
except ValueError:
return
return parent_state.requirement
......@@ -706,7 +709,7 @@ class Resolution:
@property
def requirement_trees(self):
vertex = self.activated.vertex_named(self.name)
vertex = self.activated.vertex_named(self.state.name)
return [self._requirement_tree_for(r) for r in vertex.requirements]
def _requirement_tree_for(self, requirement):
......
......@@ -42,7 +42,8 @@ class ResolutionState:
return cls(None, [], DependencyGraph(), None, None, 0, {}, [])
def __repr__(self):
return f'<{self.__class__.__name__} {self._name}>'
return f'<{self.__class__.__name__} {self._name} ' \
f'({str(self.requirement)})>'
class PossibilityState(ResolutionState):
......
{
"name": "resolves a single dependency",
"index": "django",
"requested": {
"django": "~1.4.0",
"django-debug-toolbar": ""
},
"base": [],
"resolved": [
{
"name": "django",
"version": "1.4.3",
"dependencies": []
}, {
"name": "django-debug-toolbar",
"version": "1.3.2",
"dependencies": [
{
"name": "django",
"version": "1.4.1",
"dependencies": [
]
}
]
}
],
"conflicts": []
}
{
"django": [
{
"name": "django",
"version": "1.4.1",
"dependencies": {
}
},
{
"name": "django",
"version": "1.4.3",
"dependencies": {
}
}, {
"name": "django",
"version": "2.0.1",
"dependencies": {
}
}
],
"django-debug-toolbar": [
{
"name": "django-debug-toolbar",
"version": "1.3.2",
"dependencies": {
"django": ">=1.4.2"
}
},
{
"name": "django-debug-toolbar",
"version": "1.6.1",
"dependencies": {
"django": ">=1.8"
}
}, {
"name": "django-debug-toolbar",
"version": "1.7.2",
"dependencies": {
"django": ">=1.9"
}
}
]
}
......@@ -116,6 +116,8 @@ def assert_graph(dg, result):
packages = sorted(dg.vertices.values(), key=lambda x: x.name)
expected_packages = sorted(result.vertices.values(), key=lambda x: x.name)
print(packages)
print(expected_packages)
assert packages == expected_packages
......@@ -127,11 +129,12 @@ def assert_graph(dg, result):
'simple_with_base',
'simple_with_dependencies',
'simple_with_shared_dependencies',
'django',
]
)
def test_resolver(fixture):
c = case(fixture)
resolver = Resolver(c.index, UI())
resolver = Resolver(c.index, UI(True))
dg = resolver.resolve(c.requested, base=c.base)
assert_graph(dg, c.result)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment