Skip to content
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

Feature/fix merge graph #5467

Merged
merged 5 commits into from Jul 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 8 additions & 4 deletions conans/model/graph_lock.py
Expand Up @@ -153,7 +153,8 @@ def update_lock(self, new_lock):
if node.modified:
old_node = self._nodes[id_]
if old_node.modified:
raise ConanException("Lockfile had already modified %s" % str(node.pref))
if not old_node.pref.is_compatible_with(node.pref):
raise ConanException("Lockfile had already modified %s" % str(node.pref))
self._nodes[id_] = node

def clean_modified(self):
Expand Down Expand Up @@ -205,11 +206,14 @@ def update_check_graph(self, deps_graph, output):
if node.recipe == RECIPE_CONSUMER:
continue # If the consumer node is not found, could be a test_package
raise
if lock_node.pref and lock_node.pref.full_repr() != node.pref.full_repr():
if node.binary == BINARY_BUILD or node.id in affected:
if lock_node.pref:
# If the update is compatible (resolved complete PREV) or if the node has
# been build, then update the graph
if lock_node.pref.is_compatible_with(node.pref) or \
node.binary == BINARY_BUILD or node.id in affected:
lock_node.pref = node.pref
else:
raise ConanException("Mistmatch between lock and graph:\nLock: %s\nGraph: %s"
raise ConanException("Mismatch between lock and graph:\nLock: %s\nGraph: %s"
% (lock_node.pref.full_repr(), node.pref.full_repr()))

def lock_node(self, node, requires):
Expand Down
20 changes: 20 additions & 0 deletions conans/model/ref.py
Expand Up @@ -131,6 +131,16 @@ def copy_with_rev(self, revision):
def copy_clear_rev(self):
return ConanFileReference(self.name, self.version, self.user, self.channel, None)

def is_compatible_with(self, new_ref):
"""Returns true if the new_ref is completing the RREV field of this object but
having the rest equal """
if self.full_repr() == new_ref.full_repr():
return True
if self.copy_clear_rev() != new_ref.copy_clear_rev():
return False

return self.revision is None


class PackageReference(namedtuple("PackageReference", "ref id revision")):
""" Full package reference, e.g.:
Expand Down Expand Up @@ -177,3 +187,13 @@ def copy_clear_rev(self):

def copy_clear_revs(self):
return self.copy_with_revs(None, None)

def is_compatible_with(self, new_ref):
"""Returns true if the new_ref is completing the PREV field of this object but
having the rest equal """
if self.full_repr() == new_ref.full_repr():
return True
if not self.ref.is_compatible_with(new_ref.ref) or self.id != new_ref.id:
return False

return self.revision is None # Only the revision is different and we don't have one
46 changes: 46 additions & 0 deletions conans/test/unittests/model/ref_test.py
Expand Up @@ -152,3 +152,49 @@ def test_conanfileref(self):
ref_pattern = ConanFileReference.loads("package/*@user/channel")
self.assertFalse(check_valid_ref(ref_pattern, allow_pattern=False))
self.assertTrue(check_valid_ref(ref_pattern, allow_pattern=True))


class CompatiblePrefTest(unittest.TestCase):

def test_compatible(self):

def ok(pref1, pref2):
pref1 = PackageReference.loads(pref1)
pref2 = PackageReference.loads(pref2)
return pref1.is_compatible_with(pref2)

# Same ref is ok
self.assertTrue(ok("package/1.0@user/channel#RREV1:packageid1#PREV1",
"package/1.0@user/channel#RREV1:packageid1#PREV1"))

# Change PREV is not ok
self.assertFalse(ok("package/1.0@user/channel#RREV1:packageid1#PREV1",
"package/1.0@user/channel#RREV1:packageid1#PREV2"))

# Different ref is not ok
self.assertFalse(ok("packageA/1.0@user/channel#RREV1:packageid1#PREV1",
"packageB/1.0@user/channel#RREV1:packageid1#PREV1"))

# Different ref is not ok
self.assertFalse(ok("packageA/1.0@user/channel#RREV1:packageid1",
"packageB/1.0@user/channel#RREV1:packageid1#PREV1"))

# Different package_id is not ok
self.assertFalse(ok("packageA/1.0@user/channel#RREV1:packageid1",
"packageA/1.0@user/channel#RREV1:packageid2#PREV1"))

# Completed PREV is ok
self.assertTrue(ok("packageA/1.0@user/channel#RREV1:packageid1",
"packageA/1.0@user/channel#RREV1:packageid1#PREV1"))

# But only in order, the second ref cannot remove PREV
self.assertFalse(ok("packageA/1.0@user/channel#RREV1:packageid1#PREV1",
"packageA/1.0@user/channel#RREV1:packageid1"))

# Completing RREV is also OK
self.assertTrue(ok("packageA/1.0@user/channel:packageid1",
"packageA/1.0@user/channel#RREV1:packageid1"))

# Completing RREV and PREV is also OK
self.assertTrue(ok("packageA/1.0@user/channel:packageid1",
"packageA/1.0@user/channel#RREV:packageid1#PREV"))