south.migration: 152 total statements, 0.0% covered

Generated: Wed 2013-03-13 10:33 CET

Source file: /media/Envs/Envs/filer-gallery/lib/python2.7/site-packages/south/migration/__init__.py

Stats: 0 executed, 141 missed, 11 excluded, 76 ignored

  1. """
  2. Main migration logic.
  3. """
  4. import sys
  5. from django.core.exceptions import ImproperlyConfigured
  6. import south.db
  7. from south import exceptions
  8. from south.models import MigrationHistory
  9. from south.db import db, DEFAULT_DB_ALIAS
  10. from south.migration.migrators import (Backwards, Forwards,
  11. DryRunMigrator, FakeMigrator,
  12. LoadInitialDataMigrator)
  13. from south.migration.base import Migration, Migrations
  14. from south.migration.utils import SortedSet
  15. from south.migration.base import all_migrations
  16. from south.signals import pre_migrate, post_migrate
  17. def to_apply(forwards, done):
  18. return [m for m in forwards if m not in done]
  19. def to_unapply(backwards, done):
  20. return [m for m in backwards if m in done]
  21. def problems(pending, done):
  22. last = None
  23. if not pending:
  24. raise StopIteration()
  25. for migration in pending:
  26. if migration in done:
  27. last = migration
  28. continue
  29. if last and migration not in done:
  30. yield last, migration
  31. def forwards_problems(pending, done, verbosity):
  32. """
  33. Takes the list of linearised pending migrations, and the set of done ones,
  34. and returns the list of problems, if any.
  35. """
  36. return inner_problem_check(problems(reversed(pending), done), done, verbosity)
  37. def backwards_problems(pending, done, verbosity):
  38. return inner_problem_check(problems(pending, done), done, verbosity)
  39. def inner_problem_check(problems, done, verbosity):
  40. "Takes a set of possible problems and gets the actual issues out of it."
  41. result = []
  42. for last, migration in problems:
  43. # 'Last' is the last applied migration. Step back from it until we
  44. # either find nothing wrong, or we find something.
  45. to_check = list(last.dependencies)
  46. while to_check:
  47. checking = to_check.pop()
  48. if checking not in done:
  49. # That's bad. Error.
  50. if verbosity:
  51. print (" ! Migration %s should not have been applied "
  52. "before %s but was." % (last, checking))
  53. result.append((last, checking))
  54. else:
  55. to_check.extend(checking.dependencies)
  56. return result
  57. def check_migration_histories(histories, delete_ghosts=False, ignore_ghosts=False):
  58. "Checks that there's no 'ghost' migrations in the database."
  59. exists = SortedSet()
  60. ghosts = []
  61. for h in histories:
  62. try:
  63. m = h.get_migration()
  64. m.migration()
  65. except exceptions.UnknownMigration:
  66. ghosts.append(h)
  67. except ImproperlyConfigured:
  68. pass # Ignore missing applications
  69. else:
  70. exists.add(m)
  71. if ghosts:
  72. # They may want us to delete ghosts.
  73. if delete_ghosts:
  74. for h in ghosts:
  75. h.delete()
  76. elif not ignore_ghosts:
  77. raise exceptions.GhostMigrations(ghosts)
  78. return exists
  79. def get_dependencies(target, migrations):
  80. forwards = list
  81. backwards = list
  82. if target is None:
  83. backwards = migrations[0].backwards_plan
  84. else:
  85. forwards = target.forwards_plan
  86. # When migrating backwards we want to remove up to and
  87. # including the next migration up in this app (not the next
  88. # one, that includes other apps)
  89. migration_before_here = target.next()
  90. if migration_before_here:
  91. backwards = migration_before_here.backwards_plan
  92. return forwards, backwards
  93. def get_direction(target, applied, migrations, verbosity, interactive):
  94. # Get the forwards and reverse dependencies for this target
  95. forwards, backwards = get_dependencies(target, migrations)
  96. # Is the whole forward branch applied?
  97. problems = None
  98. forwards = forwards()
  99. workplan = to_apply(forwards, applied)
  100. if not workplan:
  101. # If they're all applied, we only know it's not backwards
  102. direction = None
  103. else:
  104. # If the remaining migrations are strictly a right segment of
  105. # the forwards trace, we just need to go forwards to our
  106. # target (and check for badness)
  107. problems = forwards_problems(forwards, applied, verbosity)
  108. direction = Forwards(verbosity=verbosity, interactive=interactive)
  109. if not problems:
  110. # What about the whole backward trace then?
  111. backwards = backwards()
  112. missing_backwards = to_apply(backwards, applied)
  113. if missing_backwards != backwards:
  114. # If what's missing is a strict left segment of backwards (i.e.
  115. # all the higher migrations) then we need to go backwards
  116. workplan = to_unapply(backwards, applied)
  117. problems = backwards_problems(backwards, applied, verbosity)
  118. direction = Backwards(verbosity=verbosity, interactive=interactive)
  119. return direction, problems, workplan
  120. def get_migrator(direction, db_dry_run, fake, load_initial_data):
  121. if not direction:
  122. return direction
  123. if db_dry_run:
  124. direction = DryRunMigrator(migrator=direction, ignore_fail=False)
  125. elif fake:
  126. direction = FakeMigrator(migrator=direction)
  127. elif load_initial_data:
  128. direction = LoadInitialDataMigrator(migrator=direction)
  129. return direction
  130. def get_unapplied_migrations(migrations, applied_migrations):
  131. applied_migration_names = ['%s.%s' % (mi.app_name,mi.migration) for mi in applied_migrations]
  132. for migration in migrations:
  133. is_applied = '%s.%s' % (migration.app_label(), migration.name()) in applied_migration_names
  134. if not is_applied:
  135. yield migration
  136. def migrate_app(migrations, target_name=None, merge=False, fake=False, db_dry_run=False, yes=False, verbosity=0, load_initial_data=False, skip=False, database=DEFAULT_DB_ALIAS, delete_ghosts=False, ignore_ghosts=False, interactive=False):
  137. app_label = migrations.app_label()
  138. verbosity = int(verbosity)
  139. # Fire off the pre-migrate signal
  140. pre_migrate.send(None, app=app_label)
  141. # If there aren't any, quit quizically
  142. if not migrations:
  143. print "? You have no migrations for the '%s' app. You might want some." % app_label
  144. return
  145. # Load the entire dependency graph
  146. Migrations.calculate_dependencies()
  147. # Check there's no strange ones in the database
  148. applied_all = MigrationHistory.objects.filter(applied__isnull=False).order_by('applied').using(database)
  149. applied = applied_all.filter(app_name=app_label).using(database)
  150. south.db.db = south.db.dbs[database]
  151. Migrations.invalidate_all_modules()
  152. south.db.db.debug = (verbosity > 1)
  153. if target_name == 'current-1':
  154. if applied.count() > 1:
  155. previous_migration = applied[applied.count() - 2]
  156. if verbosity:
  157. print 'previous_migration: %s (applied: %s)' % (previous_migration.migration, previous_migration.applied)
  158. target_name = previous_migration.migration
  159. else:
  160. if verbosity:
  161. print 'previous_migration: zero'
  162. target_name = 'zero'
  163. elif target_name == 'current+1':
  164. try:
  165. first_unapplied_migration = get_unapplied_migrations(migrations, applied).next()
  166. target_name = first_unapplied_migration.name()
  167. except StopIteration:
  168. target_name = None
  169. applied_all = check_migration_histories(applied_all, delete_ghosts, ignore_ghosts)
  170. # Guess the target_name
  171. target = migrations.guess_migration(target_name)
  172. if verbosity:
  173. if target_name not in ('zero', None) and target.name() != target_name:
  174. print " - Soft matched migration %s to %s." % (target_name,
  175. target.name())
  176. print "Running migrations for %s:" % app_label
  177. # Get the forwards and reverse dependencies for this target
  178. direction, problems, workplan = get_direction(target, applied_all, migrations,
  179. verbosity, interactive)
  180. if problems and not (merge or skip):
  181. raise exceptions.InconsistentMigrationHistory(problems)
  182. # Perform the migration
  183. migrator = get_migrator(direction, db_dry_run, fake, load_initial_data)
  184. if migrator:
  185. migrator.print_title(target)
  186. success = migrator.migrate_many(target, workplan, database)
  187. # Finally, fire off the post-migrate signal
  188. if success:
  189. post_migrate.send(None, app=app_label)
  190. else:
  191. if verbosity:
  192. # Say there's nothing.
  193. print '- Nothing to migrate.'
  194. # If we have initial data enabled, and we're at the most recent
  195. # migration, do initial data.
  196. # Note: We use a fake Forwards() migrator here. It's never used really.
  197. if load_initial_data:
  198. migrator = LoadInitialDataMigrator(migrator=Forwards(verbosity=verbosity))
  199. migrator.load_initial_data(target, db=database)
  200. # Send signal.
  201. post_migrate.send(None, app=app_label)