def test_abspath_overlap(self): base = "/foo/bar" # simple self.assertEqual('SAME_AS', realpath_relation("/foo", "/foo")) self.assertEqual('SAME_AS', realpath_relation("/", "/")) # denormalized self.assertEqual('SAME_AS', realpath_relation("/foo/.", "/foo/bar/../")) # subdir self.assertEqual('PARENT_OF', realpath_relation("/foo", "/foo/bar/baz/bam")) self.assertEqual('CHILD_OF', realpath_relation("/foo/bar/baz/bam", "/foo")) ## Negatives self.assertEqual(None, realpath_relation("/foo", "/bar")) self.assertEqual(None, realpath_relation("/foo", "/foo2")) self.assertEqual(None, realpath_relation("/foo/bar", "/foo/ba")) self.assertEqual(None, realpath_relation("/foo/ba", "/foo/bar/baz")) self.assertEqual(None, realpath_relation("/foo/bar/baz", "/foo/ba"))
def insert_element(self, new_config_elt, merge_strategy='KillAppend'): """ Insert ConfigElement to self.trees, checking for duplicate local-name or path first. In case local_name matches, follow given strategy - KillAppend (default): remove old element, append new at the end - MergeReplace: remove first hit, insert new at that position. - MergeKeep: Discard new element In case local path matches but local name does not, raise Exception :returns: the action performed None, 'Append', 'KillAppend', 'MergeReplace', 'MergeKeep' """ removals = [] replaced = False for index, loop_elt in enumerate(self.trees): # if paths are os.path.realpath, no symlink problems. relationship = realpath_relation(loop_elt.get_path(), new_config_elt.get_path()) if relationship == 'SAME_AS': if os.path.normpath(loop_elt.get_local_name()) != os.path.normpath(new_config_elt.get_local_name()): raise MultiProjectException("Elements with different local_name target the same path: %s, %s" % (loop_elt, new_config_elt)) else: if (loop_elt == new_config_elt): return None if (merge_strategy == 'MergeReplace' or (merge_strategy == 'KillAppend' and index == len(self.trees) - 1)): self.trees[index] = new_config_elt # keep looping to check for overlap when replacing non- # scm with scm entry replaced = True if (loop_elt.is_vcs_element or not new_config_elt.is_vcs_element): return 'MergeReplace' elif merge_strategy == 'KillAppend': removals.append(loop_elt) elif merge_strategy == 'MergeKeep': return 'MergeKeep' else: raise LookupError( "No such merge strategy: %s" % str(merge_strategy)) elif ((relationship == 'CHILD_OF' and new_config_elt.is_vcs_element()) or (relationship == 'PARENT_OF' and loop_elt.is_vcs_element())): # we do not allow any elements to be children of scm elements # to allow for parallel updates and because wstool may # delete scm folders on update, and thus subfolders can be # deleted with their parents raise MultiProjectException( "Managed Element paths overlap: %s, %s" % (loop_elt, new_config_elt)) if replaced: return 'MergeReplace' for loop_elt in removals: self.trees.remove(loop_elt) self.trees.append(new_config_elt) if len(removals) > 0: return 'KillAppend' return 'Append'
def insert_element(self, new_config_elt, merge_strategy='KillAppend'): """ Insert ConfigElement to self.trees, checking for duplicate local-name or path first. In case local_name matches, follow given strategy - KillAppend (default): remove old element, append new at the end - MergeReplace: remove first hit, insert new at that position. - MergeKeep: Discard new element In case local path matches but local name does not, raise Exception :returns: the action performed None, 'Append', 'KillAppend', 'MergeReplace', 'MergeKeep' """ removals = [] replaced = False for index, loop_elt in enumerate(self.trees): # if paths are os.path.realpath, no symlink problems. relationship = realpath_relation(loop_elt.get_path(), new_config_elt.get_path()) if relationship == 'SAME_AS': if os.path.normpath( loop_elt.get_local_name()) != os.path.normpath( new_config_elt.get_local_name()): raise MultiProjectException( "Elements with different local_name target the same path: %s, %s" % (loop_elt, new_config_elt)) else: if (loop_elt == new_config_elt): return None if (merge_strategy == 'MergeReplace' or (merge_strategy == 'KillAppend' and index == len(self.trees) - 1)): self.trees[index] = new_config_elt # keep looping to check for overlap when replacing non- # scm with scm entry replaced = True if (loop_elt.is_vcs_element or not new_config_elt.is_vcs_element): return 'MergeReplace' elif merge_strategy == 'KillAppend': removals.append(loop_elt) elif merge_strategy == 'MergeKeep': return 'MergeKeep' else: raise LookupError("No such merge strategy: %s" % str(merge_strategy)) elif ((relationship == 'CHILD_OF' and new_config_elt.is_vcs_element()) or (relationship == 'PARENT_OF' and loop_elt.is_vcs_element())): # we do not allow any elements to be children of scm elements # to allow for parallel updates and because wstool may # delete scm folders on update, and thus subfolders can be # deleted with their parents raise MultiProjectException( "Managed Element paths overlap: %s, %s" % (loop_elt, new_config_elt)) if replaced: return 'MergeReplace' for loop_elt in removals: self.trees.remove(loop_elt) self.trees.append(new_config_elt) if len(removals) > 0: return 'KillAppend' return 'Append'