Commits

Andrew Godwin committed dbc3eb7

Start of rebase work.

Comments (0)

Files changed (4)

south/migration/__init__.py

     forwards, backwards = get_dependencies(target, migrations)
     # Is the whole forward branch applied?
     problems = None
-    forwards = forwards()
+    forwards = forwards(allow_rebase=not applied)
     workplan = to_apply(forwards, applied)
     if not workplan:
         # If they're all applied, we only know it's not backwards

south/migration/base.py

         return self.migrations[index]
     next = memoize(next)
     
+    def is_base(self):
+        """
+        Returns whether this migration is a 'base' migration - one which is
+        a safe place for the migrator to stop.
+        This is true if it's an initial migration, or if it's been created by
+        rebase.
+        """
+        return (self.previous() is None) or getattr(self.migration_class(), "rebase", False) 
+    is_base = memoize(is_base)
+    
     def _get_dependency_objects(self, attrname):
         """
         Given the name of an attribute (depends_on or needed_by), either yields
     def backwards(self):
         return self.migration_instance().backwards
 
-    def forwards_plan(self):
+    def forwards_plan(self, allow_rebase=False):
         """
         Returns a list of Migration objects to be applied, in order.
 
         This list includes `self`, which will be applied last.
         """
-        return depends(self, lambda x: x.dependencies)
-
-    def _backwards_plan(self):
-        return depends(self, lambda x: x.dependents)
+        base_plan = depends(self, lambda x: x.dependencies)
+        new_plan = []
+        for item in reversed(base_plan):
+            if allow_rebase:
+                new_plan.insert(0, item)
+                if item.is_base():
+                    break
+            else:
+                if not item.is_base():
+                    new_plan.insert(0, item)
+        return new_plan
 
     def backwards_plan(self):
         """
 
         This list includes `self`, which will be unapplied last.
         """
-        return list(self._backwards_plan())
+        return depends(self, lambda x: x.dependents)
 
     def is_before(self, other):
         if self.migrations == other.migrations:

south/tests/logic.py

             ],
             otherfakeapp['0003_third'].forwards_plan(),
         )
+    
+    def test_rebase(self):
+        """
+        Tests that the rebase logic correctly starts at a rebase migration,
+        but only if we're doing a fresh install.
+        """
+        pass
 
 
 class TestMigrationUtils(Monkeypatcher):
 
 class BaseMigration(object):
     
+    no_dry_run = False
+    depends_on = []
+    needed_by = []
+    rebase = False
+    
     def gf(self, field_name):
         "Gets a field by absolute reference."
         return ask_for_it_by_name(field_name)