south.management.commands.migrate: 123 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/management/commands/migrate.py

Stats: 0 executed, 113 missed, 10 excluded, 137 ignored

  1. """
  2. Migrate management command.
  3. """
  4. import os.path, re, sys
  5. from optparse import make_option
  6. from django.core.management.base import BaseCommand
  7. from django.conf import settings
  8. from django.utils.importlib import import_module
  9. from south import migration
  10. from south.migration import Migrations
  11. from south.exceptions import NoMigrations
  12. from south.db import DEFAULT_DB_ALIAS
  13. class Command(BaseCommand):
  14. option_list = BaseCommand.option_list + (
  15. make_option('--all', action='store_true', dest='all_apps', default=False,
  16. help='Run the specified migration for all apps.'),
  17. make_option('--list', action='store_true', dest='show_list', default=False,
  18. help='List migrations noting those that have been applied'),
  19. make_option('--changes', action='store_true', dest='show_changes', default=False,
  20. help='List changes for migrations'),
  21. make_option('--skip', action='store_true', dest='skip', default=False,
  22. help='Will skip over out-of-order missing migrations'),
  23. make_option('--merge', action='store_true', dest='merge', default=False,
  24. help='Will run out-of-order missing migrations as they are - no rollbacks.'),
  25. make_option('--no-initial-data', action='store_true', dest='no_initial_data', default=False,
  26. help='Skips loading initial data if specified.'),
  27. make_option('--fake', action='store_true', dest='fake', default=False,
  28. help="Pretends to do the migrations, but doesn't actually execute them."),
  29. make_option('--db-dry-run', action='store_true', dest='db_dry_run', default=False,
  30. help="Doesn't execute the SQL generated by the db methods, and doesn't store a record that the migration(s) occurred. Useful to test migrations before applying them."),
  31. make_option('--delete-ghost-migrations', action='store_true', dest='delete_ghosts', default=False,
  32. help="Tells South to delete any 'ghost' migrations (ones in the database but not on disk)."),
  33. make_option('--ignore-ghost-migrations', action='store_true', dest='ignore_ghosts', default=False,
  34. help="Tells South to ignore any 'ghost' migrations (ones in the database but not on disk) and continue to apply new migrations."),
  35. make_option('--noinput', action='store_false', dest='interactive', default=True,
  36. help='Tells Django to NOT prompt the user for input of any kind.'),
  37. make_option('--database', action='store', dest='database',
  38. default=DEFAULT_DB_ALIAS, help='Nominates a database to synchronize. '
  39. 'Defaults to the "default" database.'),
  40. )
  41. if '--verbosity' not in [opt.get_opt_string() for opt in BaseCommand.option_list]:
  42. option_list += (
  43. make_option('--verbosity', action='store', dest='verbosity', default='1',
  44. type='choice', choices=['0', '1', '2'],
  45. help='Verbosity level; 0=minimal output, 1=normal output, 2=all output'),
  46. )
  47. help = "Runs migrations for all apps."
  48. args = "[appname] [migrationname|zero] [--all] [--list] [--skip] [--merge] [--no-initial-data] [--fake] [--db-dry-run] [--database=dbalias]"
  49. def handle(self, app=None, target=None, skip=False, merge=False, backwards=False, fake=False, db_dry_run=False, show_list=False, show_changes=False, database=DEFAULT_DB_ALIAS, delete_ghosts=False, ignore_ghosts=False, **options):
  50. # NOTE: THIS IS DUPLICATED FROM django.core.management.commands.syncdb
  51. # This code imports any module named 'management' in INSTALLED_APPS.
  52. # The 'management' module is the preferred way of listening to post_syncdb
  53. # signals, and since we're sending those out with create_table migrations,
  54. # we need apps to behave correctly.
  55. for app_name in settings.INSTALLED_APPS:
  56. try:
  57. import_module('.management', app_name)
  58. except ImportError, exc:
  59. msg = exc.args[0]
  60. if not msg.startswith('No module named') or 'management' not in msg:
  61. raise
  62. # END DJANGO DUPE CODE
  63. # if all_apps flag is set, shift app over to target
  64. if options.get('all_apps', False):
  65. target = app
  66. app = None
  67. # Migrate each app
  68. if app:
  69. try:
  70. apps = [Migrations(app)]
  71. except NoMigrations:
  72. print "The app '%s' does not appear to use migrations." % app
  73. print "./manage.py migrate " + self.args
  74. return
  75. else:
  76. apps = list(migration.all_migrations())
  77. # Do we need to show the list of migrations?
  78. if show_list and apps:
  79. list_migrations(apps, database, **options)
  80. if show_changes and apps:
  81. show_migration_changes(apps)
  82. if not (show_list or show_changes):
  83. for app in apps:
  84. result = migration.migrate_app(
  85. app,
  86. target_name = target,
  87. fake = fake,
  88. db_dry_run = db_dry_run,
  89. verbosity = int(options.get('verbosity', 0)),
  90. interactive = options.get('interactive', True),
  91. load_initial_data = not options.get('no_initial_data', False),
  92. merge = merge,
  93. skip = skip,
  94. database = database,
  95. delete_ghosts = delete_ghosts,
  96. ignore_ghosts = ignore_ghosts,
  97. )
  98. if result is False:
  99. sys.exit(1) # Migration failed, so the command fails.
  100. def list_migrations(apps, database = DEFAULT_DB_ALIAS, **options):
  101. """
  102. Prints a list of all available migrations, and which ones are currently applied.
  103. Accepts a list of Migrations instances.
  104. """
  105. from south.models import MigrationHistory
  106. applied_migrations = MigrationHistory.objects.filter(app_name__in=[app.app_label() for app in apps])
  107. if database != DEFAULT_DB_ALIAS:
  108. applied_migrations = applied_migrations.using(database)
  109. applied_migration_names = ['%s.%s' % (mi.app_name,mi.migration) for mi in applied_migrations]
  110. print
  111. for app in apps:
  112. print " " + app.app_label()
  113. # Get the migrations object
  114. for migration in app:
  115. if migration.app_label() + "." + migration.name() in applied_migration_names:
  116. applied_migration = applied_migrations.get(app_name=migration.app_label(), migration=migration.name())
  117. print format_migration_list_item(migration.name(), applied=applied_migration.applied, **options)
  118. else:
  119. print format_migration_list_item(migration.name(), applied=False, **options)
  120. print
  121. def show_migration_changes(apps):
  122. """
  123. Prints a list of all available migrations, and which ones are currently applied.
  124. Accepts a list of Migrations instances.
  125. Much simpler, less clear, and much less robust version:
  126. grep "ing " migrations/*.py
  127. """
  128. for app in apps:
  129. print app.app_label()
  130. # Get the migrations objects
  131. migrations = [migration for migration in app]
  132. # we use reduce to compare models in pairs, not to generate a value
  133. reduce(diff_migrations, migrations)
  134. def format_migration_list_item(name, applied=True, **options):
  135. if applied:
  136. if int(options.get('verbosity')) >= 2:
  137. return ' (*) %-80s (applied %s)' % (name, applied)
  138. else:
  139. return ' (*) %s' % name
  140. else:
  141. return ' ( ) %s' % name
  142. def diff_migrations(migration1, migration2):
  143. def model_name(models, model):
  144. return models[model].get('Meta', {}).get('object_name', model)
  145. def field_name(models, model, field):
  146. return '%s.%s' % (model_name(models, model), field)
  147. print " " + migration2.name()
  148. models1 = migration1.migration_class().models
  149. models2 = migration2.migration_class().models
  150. # find new models
  151. for model in models2.keys():
  152. if not model in models1.keys():
  153. print ' added model %s' % model_name(models2, model)
  154. # find removed models
  155. for model in models1.keys():
  156. if not model in models2.keys():
  157. print ' removed model %s' % model_name(models1, model)
  158. # compare models
  159. for model in models1:
  160. if model in models2:
  161. # find added fields
  162. for field in models2[model]:
  163. if not field in models1[model]:
  164. print ' added field %s' % field_name(models2, model, field)
  165. # find removed fields
  166. for field in models1[model]:
  167. if not field in models2[model]:
  168. print ' removed field %s' % field_name(models1, model, field)
  169. # compare fields
  170. for field in models1[model]:
  171. if field in models2[model]:
  172. name = field_name(models1, model, field)
  173. # compare field attributes
  174. field_value1 = models1[model][field]
  175. field_value2 = models2[model][field]
  176. # if a field has become a class, or vice versa
  177. if type(field_value1) != type(field_value2):
  178. print ' type of %s changed from %s to %s' % (
  179. name, field_value1, field_value2)
  180. # if class
  181. elif isinstance(field_value1, dict):
  182. # print ' %s is a class' % name
  183. pass
  184. # else regular field
  185. else:
  186. type1, attr_list1, field_attrs1 = models1[model][field]
  187. type2, attr_list2, field_attrs2 = models2[model][field]
  188. if type1 != type2:
  189. print ' %s type changed from %s to %s' % (
  190. name, type1, type2)
  191. if attr_list1 != []:
  192. print ' %s list %s is not []' % (
  193. name, attr_list1)
  194. if attr_list2 != []:
  195. print ' %s list %s is not []' % (
  196. name, attr_list2)
  197. if attr_list1 != attr_list2:
  198. print ' %s list changed from %s to %s' % (
  199. name, attr_list1, attr_list2)
  200. # find added field attributes
  201. for attr in field_attrs2:
  202. if not attr in field_attrs1:
  203. print ' added %s attribute %s=%s' % (
  204. name, attr, field_attrs2[attr])
  205. # find removed field attributes
  206. for attr in field_attrs1:
  207. if not attr in field_attrs2:
  208. print ' removed attribute %s(%s=%s)' % (
  209. name, attr, field_attrs1[attr])
  210. # compare field attributes
  211. for attr in field_attrs1:
  212. if attr in field_attrs2:
  213. value1 = field_attrs1[attr]
  214. value2 = field_attrs2[attr]
  215. if value1 != value2:
  216. print ' %s attribute %s changed from %s to %s' % (
  217. name, attr, value1, value2)
  218. return migration2