def test_upgrade_from_empty(): patchrepo = PatchRepository() patch1 = Patch('patch1', depends_on_names=[('patch2', False)]) patch2 = Patch('patch2', depends_on_names=[('patch3', False)]) patch3 = Patch('patch3', depends_on_names=[]) patchrepo.add_patches(patch1, patch2, patch3) patchrepo.resolve_dependencies() plan = generate_upgrade_plan(applied_patches=[], to_be_applied_patches=[patch1]) eq_(plan, [patch3, patch2, patch1]) plan = generate_upgrade_plan(applied_patches=[], to_be_applied_patches=[patch3]) eq_(plan, [patch3])
def test_complex_upgrade(): patchrepo = PatchRepository() patch1 = Patch('patch1', depends_on_names=[('patch2', False)]) patch2 = Patch('patch2', depends_on_names=[('patch3', False), ('patch4', False)]) patch3 = Patch('patch3', depends_on_names=[('patch4', False), ('patch5', False)]) patch4 = Patch('patch4', depends_on_names=[]) patch5 = Patch('patch5', depends_on_names=[]) patchrepo.add_patches(patch1, patch2, patch3, patch4, patch5) patchrepo.resolve_dependencies() plan = generate_upgrade_plan(applied_patches=[patch4, patch5], to_be_applied_patches=[patch1]) eq_(plan, [patch3, patch2, patch1])
def upgrade_patches(self, patches, execute_sql=True): dbrepo = self._get_repo() applied_patches = self.applied_patches plan = generate_upgrade_plan(applied_patches=applied_patches, to_be_applied_patches=patches) for patch in plan: print "applying patch '%s'" % patch.name self.sess.add(AppliedPatch(dbrepo.repository_id, patch.name)) if patch.upgrade_sql is not None and execute_sql: for patch_name in patch.missing_deps: print " (ignoring optional missing patch '%s')" % patch_name with _TranslateErrors("patch upgrade failed '%s'" % ( patch.name)): execute_script(self.sess, patch.upgrade_sql) return plan
def calculate_minimal_deps(self, patches): """Returns the minimal set of patches that is equivalent to `patches`. The returned list will be equal to or smaller than `patches`, due to potentially existing dependencies between the patches. """ # Note: This is a primitive algorithm and slow implementation. It isn't # intended for large sets of patches. patches = set(patches) minimal_patches = patches.copy() for patch in patches: # Generate recursive list of dependencies introduced by this patch. patch_deps = set(generate_upgrade_plan(applied_patches=[], to_be_applied_patches=[patch])) # See whether any of the other patches are mentioned in the full # dependency list. for other_patch in patches: if other_patch == patch: continue if other_patch in patch_deps and other_patch in minimal_patches: # `other_patch` is part of the dependency list of `patch`, so # (assuming an acyclic graph) it is not part the minimal # patch set. minimal_patches.remove(other_patch) return minimal_patches