def test_init_on_fresh_db_creates_new_table(self):
    si = MigrationState()

    self.assert_equal(False, si.migration_table_present())

    si.init()

    self.assert_equal(True, si.migration_table_present())
Example #2
0
  def test_table_present_methods(self):
    si = MigrationState()

    self.assert_equal(False, si.migration_table_present())

    self.cursor.execute(create_new)

    self.assert_equal(True, si.migration_table_present())
  def test_table_present_methods(self):
    si = MigrationState()

    self.assert_equal(False, si.migration_table_present())

    self.cursor.execute(create_new)

    self.assert_equal(True, si.migration_table_present())
  def test_init_on_initialized_db_does_nothing(self):
    self.cursor.execute(create_new)

    si = MigrationState()

    self.assert_equal(True, si.migration_table_present())

    si.init()

    self.assert_equal(True, si.migration_table_present())
Example #5
0
  def test_all_migrations_applied(self):
    db = MigrationDb(migrations = ['001_foo', '002_DEV_bar', '005_omg', '006_DEV_hello'])
    si = MigrationState(migration_db=db)
    si.init()

    si.mark_as_applied('005_omg')
    si.mark_as_applied('001_foo')
    si.mark_as_applied('009_bogus')

    self.assert_equal(['001_foo', '005_omg', '009_bogus'], si.all_migrations_applied())
  def test_all_migrations_applied(self):
    db = MigrationDb(migrations = ['001_foo', '002_DEV_bar', '005_omg', '006_DEV_hello'])
    si = MigrationState(migration_db=db)
    si.init()

    si.mark_as_applied('005_omg')
    si.mark_as_applied('001_foo')
    si.mark_as_applied('009_bogus')

    self.assert_equal(['001_foo', '005_omg', '009_bogus'], si.all_migrations_applied())
Example #7
0
  def test_init_on_fresh_db_creates_new_table(self):
    si = MigrationState()

    self.assert_equal(False, si.migration_table_present())

    si.init()

    self.assert_equal(True, si.migration_table_present())
Example #8
0
  def test_init_on_initialized_db_does_nothing(self):
    self.cursor.execute(create_new)

    si = MigrationState()

    self.assert_equal(True, si.migration_table_present())

    si.init()

    self.assert_equal(True, si.migration_table_present())
Example #9
0
    def test_when_doing_something_then_loggged(self):
        db = MigrationDb(directory=self.mock_migrations_dir)
        db.warn = WarningsMocker()
        si = MigrationState(migration_db=db, dev=True)
        si.init()

        si.apply("001_foo")
        si.mark_as_unapplied("001_foo")
        si.apply("001_foo")
        si.mark_as_applied("005_omg")
        si.unapply("001_foo")

        self.assert_equal(
            [
                ("apply", "001_foo", "success"),
                ("mark_as_unapplied", "001_foo", "success"),
                ("apply", "001_foo", "success"),
                ("mark_as_applied", "005_omg", "success"),
                ("unapply", "001_foo", "success"),
            ],
            [row[:3] for row in get_log()],
        )
        self.assert_equal(True, isinstance(get_log()[0][3], datetime))
  def test_plan(self):
    db = MigrationDb(migrations = ['001_foo', '002_bar', '005_omg', '005_hello'])
    si = MigrationState(migration_db=db)

    si.init()

    self.assert_plans(si,
      ['apply', '1'],         [('001_foo', 'up')],
      ['apply', '001_foo'],   [('001_foo', 'up')],
      ['apply', '1', '2'],    [('001_foo', 'up'), ('002_bar', 'up')],
      ['unapply', '001_foo'], [],
      ['unapply', '1', '2'],  [],

      ['all'],                [('001_foo', 'up'), ('002_bar', 'up'), ('005_hello', 'up'), ('005_omg', 'up')],
      ['up'],                 [('001_foo', 'up')],
      ['down'],               [],

      ['to', '1'],            [('001_foo', 'up')],
      ['to', '2'],            [('001_foo', 'up'), ('002_bar', 'up')],
      ['upto', '2'],          [('001_foo', 'up'), ('002_bar', 'up')],
      ['upto', '002_bar'],    [('001_foo', 'up'), ('002_bar', 'up')],
      ['upto', '4'],          [('001_foo', 'up'), ('002_bar', 'up')],
      ['upto', '004_foo'],    NoSuchMigrationError,
      ['upto', '5'],          AmbiguousMigrationNameError,
      ['upto', '005_hello'],  [('001_foo', 'up'), ('002_bar', 'up'), ('005_hello', 'up')],
      ['upto', '005_omg'],    [('001_foo', 'up'), ('002_bar', 'up'), ('005_hello', 'up'), ('005_omg', 'up')],
      ['downto', '1'],        [],
      ['downto', '2'],        [],
    )

    si.mark_as_applied('002_bar')

    self.assert_plans(si,
      ['apply', '1'],         [('001_foo', 'up')],
      ['apply', '001_foo'],   [('001_foo', 'up')],
      ['apply', '1', '2'],    [('001_foo', 'up')],
      ['unapply', '001_foo'], [],
      ['unapply', '1', '2'],  [('002_bar', 'down')],

      ['all'],                [('001_foo', 'up'), ('005_hello', 'up'), ('005_omg', 'up')],
      ['up'],                 [('001_foo', 'up')],
      ['down'],               [('002_bar', 'down')],

      ['to', '1'],            [('002_bar', 'down'), ('001_foo', 'up')],
      ['to', '2'],            [('001_foo', 'up')],
      ['upto', '2'],          [('001_foo', 'up')],
      ['upto', '002_bar'],    [('001_foo', 'up')],
      ['upto', '4'],          [('001_foo', 'up')],
      ['upto', '004_foo'],    NoSuchMigrationError,
      ['upto', '5'],          AmbiguousMigrationNameError,
      ['upto', '005_hello'],  [('001_foo', 'up'), ('005_hello', 'up')],
      ['upto', '005_omg'],    [('001_foo', 'up'), ('005_hello', 'up'), ('005_omg', 'up')],
      ['downto', '1'],        [('002_bar', 'down')],
      ['downto', '2'],        [],
    )

    si.mark_as_applied('001_foo')

    self.assert_plans(si,
      ['apply', '1'],         [],
      ['apply', '001_foo'],   [],
      ['apply', '1', '2'],    [],
      ['unapply', '001_foo'], [('001_foo', 'down')],
      ['unapply', '1', '2'],  [('001_foo', 'down'), ('002_bar', 'down')],

      ['all'],                [('005_hello', 'up'), ('005_omg', 'up')],
      ['up'],                 [('005_hello', 'up')],
      ['down'],               [('002_bar', 'down')],

      ['to', '1'],            [('002_bar', 'down')],
      ['to', '2'],            [],
      ['upto', '2'],          [],
      ['upto', '002_bar'],    [],
      ['upto', '4'],          [],
      ['upto', '004_foo'],    NoSuchMigrationError,
      ['upto', '5'],          AmbiguousMigrationNameError,
      ['upto', '005_hello'],  [('005_hello', 'up')],
      ['upto', '005_omg'],    [('005_hello', 'up'), ('005_omg', 'up')],
      ['downto', '1'],        [('002_bar', 'down')],
      ['downto', '2'],        [],
    )

    si.mark_as_unapplied('002_bar')

    self.assert_plans(si,
      ['apply', '1'],         [],
      ['apply', '001_foo'],   [],
      ['apply', '1', '2'],    [('002_bar', 'up')],
      ['unapply', '001_foo'], [('001_foo', 'down')],
      ['unapply', '1', '2'],  [('001_foo', 'down')],

      ['all'],                [('002_bar', 'up'), ('005_hello', 'up'), ('005_omg', 'up')],
      ['up'],                 [('002_bar', 'up')],
      ['down'],               [('001_foo', 'down')],

      ['to', '1'],            [],
      ['to', '2'],            [('002_bar', 'up')],
      ['upto', '2'],          [('002_bar', 'up')],
      ['upto', '002_bar'],    [('002_bar', 'up')],
      ['upto', '4'],          [('002_bar', 'up')],
      ['upto', '004_foo'],    NoSuchMigrationError,
      ['upto', '5'],          AmbiguousMigrationNameError,
      ['upto', '005_hello'],  [('002_bar', 'up'), ('005_hello', 'up')],
      ['upto', '005_omg'],    [('002_bar', 'up'), ('005_hello', 'up'), ('005_omg', 'up')],
      ['downto', '1'],        [],
      ['downto', '2'],        [],
    )

    si.mark_as_applied('002_bar')
    si.mark_as_applied('005_hello')
    si.mark_as_applied('005_omg')

    self.assert_plans(si,
      ['apply', '1'],         [],
      ['apply', '001_foo'],   [],
      ['apply', '1', '2'],    [],
      ['unapply', '001_foo'], [('001_foo', 'down')],
      ['unapply', '1', '2'],  [('001_foo', 'down'), ('002_bar', 'down')],

      ['all'],                [],
      ['up'],                 [],
      ['down'],               [('005_omg', 'down')],

      ['to', '1'],            [('005_omg', 'down'), ('005_hello', 'down'), ('002_bar', 'down')],
      ['to', '2'],            [('005_omg', 'down'), ('005_hello', 'down')],
      ['upto', '2'],          [],
      ['upto', '002_bar'],    [],
      ['upto', '4'],          [],
      ['upto', '004_foo'],    NoSuchMigrationError,
      ['upto', '5'],          AmbiguousMigrationNameError,
      ['upto', '005_hello'],  [],
      ['upto', '005_omg'],    [],
      ['downto', '1'],        [('005_omg', 'down'), ('005_hello', 'down'), ('002_bar', 'down')],
      ['downto', '2'],        [('005_omg', 'down'), ('005_hello', 'down')],
    )
  def test_applying_and_unapplying(self):
    def assert_applied(f, b, h):
      self.assert_equal([f, b, h], [si.is_applied('001_foo'), si.is_applied('002_bar'), si.is_applied('005_hello')])

    si = MigrationState()
    self.cursor.execute(create_new)

    assert_applied(False, False, False)

    si.mark_as_applied('001_foo')
    assert_applied(True, False, False)

    si.mark_as_applied('005_hello')
    assert_applied(True, False, True)

    si.mark_as_applied('005_hello')
    assert_applied(True, False, True)

    si.mark_as_unapplied('002_bar')
    assert_applied(True, False, True)

    si.mark_as_unapplied('005_hello')
    assert_applied(True, False, False)

    si.mark_as_applied('002_bar')
    assert_applied(True, True, False)
Example #12
0
  def test_plan_with_dev(self):
    # NOTE: si.mark_as_applied modifies global state, not si (MigrationState) object.
    #       There is only one meaningful MigrationState object per database,
    #       so it's an almost-singleton unless we support multiple databases at the same time.
    #       This makes testing quite ugly.
    db = MigrationDb(migrations = ['001_foo', '002_DEV_bar', '005_omg', '006_DEV_hello'])

    si = MigrationState(migration_db=db)
    si.init()
    self.assert_plans(si,
      ['up'],        [('001_foo', 'up')],
      ['upto', '5'], [('001_foo', 'up'), ('005_omg', 'up')],
      ['upto', '6'], [('001_foo', 'up'), ('005_omg', 'up')],
      ['all'],       [('001_foo', 'up'), ('005_omg', 'up')],
    )

    si = MigrationState(migration_db=db, dev=True)
    si.init()
    self.assert_plans(si,
      ['up'],        [('001_foo', 'up')],
      ['upto', '5'], [('001_foo', 'up'), ('002_DEV_bar', 'up'), ('005_omg', 'up')],
      ['upto', '6'], [('001_foo', 'up'), ('002_DEV_bar', 'up'), ('005_omg', 'up'), ('006_DEV_hello', 'up')],
      ['all'],       [('001_foo', 'up'), ('002_DEV_bar', 'up'), ('005_omg', 'up'), ('006_DEV_hello', 'up')],
    )

    si.mark_as_applied('001_foo')

    si = MigrationState(migration_db=db)
    si.init()
    self.assert_plans(si,
      ['up'],        [('005_omg', 'up')],
      ['upto', '5'], [('005_omg', 'up')],
      ['upto', '6'], [('005_omg', 'up')],
      ['all'],       [('005_omg', 'up')],
    )

    si = MigrationState(migration_db=db, dev=True)
    si.init()
    self.assert_plans(si,
      ['up'],        [('002_DEV_bar', 'up')],
      ['upto', '5'], [('002_DEV_bar', 'up'), ('005_omg', 'up')],
      ['upto', '6'], [('002_DEV_bar', 'up'), ('005_omg', 'up'), ('006_DEV_hello', 'up')],
      ['all'],       [('002_DEV_bar', 'up'), ('005_omg', 'up'), ('006_DEV_hello', 'up')],
    )

    si.mark_as_applied('002_DEV_bar')

    si = MigrationState(migration_db=db)
    si.init()
    self.assert_plans(si,
      ['up'],        [('005_omg', 'up')],
      ['upto', '5'], [('005_omg', 'up')],
      ['upto', '6'], [('005_omg', 'up')],
      ['all'],       [('005_omg', 'up')],
      ['down'],      [('001_foo', 'down')], # Is it better to always assume --dev on down ?
    )

    si = MigrationState(migration_db=db, dev=True)
    si.init()
    self.assert_plans(si,
      ['up'],        [('005_omg', 'up')],
      ['upto', '5'], [('005_omg', 'up')],
      ['upto', '6'], [('005_omg', 'up'), ('006_DEV_hello', 'up')],
      ['all'],       [('005_omg', 'up'), ('006_DEV_hello', 'up')],
      ['down'],      [('002_DEV_bar', 'down')],
    )
Example #13
0
 def handle(self, *args, **options):
     try:
         migrations_dir = settings.DMIGRATIONS_DIR
     except AttributeError:
         print "You need to add DMIGRATIONS_DIR to your settings"
         return
     migration_db = MigrationDb(directory = migrations_dir)
     migration_state = MigrationState(
         migration_db = migration_db, dev = options.get('dev')
     )
     verbosity = int(options.get('verbosity', 1))
     
     if not args or args[0] == 'help':
         self.print_help(sys.argv[0], 'dmigrate')
         return
     
     elif args[0] in 'all all_hard up down upto downto to apply unapply'.split():
         migration_state.init()
         for (migration_name, action) in migration_state.plan(*args):
             migration = migration_db.load_migration_object(migration_name)
             start_time = time.time()
             if action == 'up':
                 if verbosity >= 1:
                     print "Applying migration %s" % migration.name
                 if not options.get('print_plan'):
                     migration_state.apply(migration_name)
             else:
                 if verbosity >= 1:
                     print "Unapplying migration %s" % migration.name
                 if not options.get('print_plan'):
                     migration_state.unapply(migration_name)
             if options.get('print_time'):
                 print "Migration %s ran %.1f seconds" % (migration.name, time.time() - start_time)
     
     elif args[0] == 'mark_as_applied':
         migration_state.init()
         for name in args[1:]:
             resolved_name = migration_state.resolve_name(name)
             if resolved_name == None:
                 raise NoSuchMigrationError(name)
             migration_state.mark_as_applied(resolved_name)
     
     elif args[0] == 'mark_as_unapplied':
         migration_state.init()
         for name in args[1:]:
             resolved_name = migration_state.resolve_name(name)
             if resolved_name == None:
                 raise NoSuchMigrationError(name)
             migration_state.mark_as_unapplied(resolved_name)
     
     elif args[0] == 'list':
         migration_state.init()
         for migration_name in migration_db.list():
             if migration_state.is_applied(migration_name, use_cache=True):
                print "* [+] %s" % migration_name
             else:
                print "* [ ] %s" % migration_name
         migrations_not_in_db = migration_state.applied_but_not_in_db()
         if migrations_not_in_db:
             print "These migrations are marked as applied but cannot " \
                 "be found:"
             for migration_name in migrations_not_in_db:
                 print "* [?] %s" % migration_name
         return
     
     elif args[0] == 'init':
         migration_state.init()
     
     elif args[0] == 'cat':
         for name in args[1:]:
             print open(
                 migration_db.resolve_migration_path(name), 'r'
             ).read()
         return
     
     else:
         raise CommandError(
             'Argument should be one of: list, help, up, down, all, all_hard, init, '
             'apply, unapply, to, downto, upto, mark_as_applied, '
             'mark_as_unapplied'
         )
     
     # Ensure Django permissions and content_types have been created
     # NOTE: Don't run if django_content_type doesn't exist yet.
     if table_present('django_content_type'):
         from django.contrib.auth.management import create_permissions
         from django.db import models
         for app in models.get_apps():
             if verbosity >= 1:
                 create_permissions(app, set(), 2)
             else:
                 create_permissions(app, set(), 1)
Example #14
0
  def test_plan(self):
    db = MigrationDb(migrations = ['001_foo', '002_bar', '005_omg', '005_hello'])
    si = MigrationState(migration_db=db)

    si.init()
    
    self.assert_plans(si,
      ['apply', '1'],         [('001_foo', 'up')],
      ['apply', '001_foo'],   [('001_foo', 'up')],
      ['apply', '1', '2'],    [('001_foo', 'up'), ('002_bar', 'up')],
      ['unapply', '001_foo'], [],
      ['unapply', '1', '2'],  [],

      ['all'],                [('001_foo', 'up'), ('002_bar', 'up'), ('005_hello', 'up'), ('005_omg', 'up')],
      ['up'],                 [('001_foo', 'up')],
      ['down'],               [],

      ['to', '1'],            [('001_foo', 'up')],
      ['to', '2'],            [('001_foo', 'up'), ('002_bar', 'up')],
      ['upto', '2'],          [('001_foo', 'up'), ('002_bar', 'up')],
      ['upto', '002_bar'],    [('001_foo', 'up'), ('002_bar', 'up')],
      ['upto', '4'],          [('001_foo', 'up'), ('002_bar', 'up')],
      ['upto', '004_foo'],    NoSuchMigrationError,
      ['upto', '5'],          AmbiguousMigrationNameError,
      ['upto', '005_hello'],  [('001_foo', 'up'), ('002_bar', 'up'), ('005_hello', 'up')],
      ['upto', '005_omg'],    [('001_foo', 'up'), ('002_bar', 'up'), ('005_hello', 'up'), ('005_omg', 'up')],
      ['downto', '1'],        [],
      ['downto', '2'],        [],
    )
    
    si.mark_as_applied('002_bar')

    self.assert_plans(si,
      ['apply', '1'],         [('001_foo', 'up')],
      ['apply', '001_foo'],   [('001_foo', 'up')],
      ['apply', '1', '2'],    [('001_foo', 'up')],
      ['unapply', '001_foo'], [],
      ['unapply', '1', '2'],  [('002_bar', 'down')],

      ['all'],                [('001_foo', 'up'), ('005_hello', 'up'), ('005_omg', 'up')],
      ['up'],                 [('001_foo', 'up')],
      ['down'],               [('002_bar', 'down')],

      ['to', '1'],            [('002_bar', 'down'), ('001_foo', 'up')],
      ['to', '2'],            [('001_foo', 'up')],
      ['upto', '2'],          [('001_foo', 'up')],
      ['upto', '002_bar'],    [('001_foo', 'up')],
      ['upto', '4'],          [('001_foo', 'up')],
      ['upto', '004_foo'],    NoSuchMigrationError,
      ['upto', '5'],          AmbiguousMigrationNameError,
      ['upto', '005_hello'],  [('001_foo', 'up'), ('005_hello', 'up')],
      ['upto', '005_omg'],    [('001_foo', 'up'), ('005_hello', 'up'), ('005_omg', 'up')],
      ['downto', '1'],        [('002_bar', 'down')],
      ['downto', '2'],        [],
    )

    si.mark_as_applied('001_foo')

    self.assert_plans(si,
      ['apply', '1'],         [],
      ['apply', '001_foo'],   [],
      ['apply', '1', '2'],    [],
      ['unapply', '001_foo'], [('001_foo', 'down')],
      ['unapply', '1', '2'],  [('001_foo', 'down'), ('002_bar', 'down')],

      ['all'],                [('005_hello', 'up'), ('005_omg', 'up')],
      ['up'],                 [('005_hello', 'up')],
      ['down'],               [('002_bar', 'down')],

      ['to', '1'],            [('002_bar', 'down')],
      ['to', '2'],            [],
      ['upto', '2'],          [],
      ['upto', '002_bar'],    [],
      ['upto', '4'],          [],
      ['upto', '004_foo'],    NoSuchMigrationError,
      ['upto', '5'],          AmbiguousMigrationNameError,
      ['upto', '005_hello'],  [('005_hello', 'up')],
      ['upto', '005_omg'],    [('005_hello', 'up'), ('005_omg', 'up')],
      ['downto', '1'],        [('002_bar', 'down')],
      ['downto', '2'],        [],
    )

    si.mark_as_unapplied('002_bar')

    self.assert_plans(si,
      ['apply', '1'],         [],
      ['apply', '001_foo'],   [],
      ['apply', '1', '2'],    [('002_bar', 'up')],
      ['unapply', '001_foo'], [('001_foo', 'down')],
      ['unapply', '1', '2'],  [('001_foo', 'down')],

      ['all'],                [('002_bar', 'up'), ('005_hello', 'up'), ('005_omg', 'up')],
      ['up'],                 [('002_bar', 'up')],
      ['down'],               [('001_foo', 'down')],

      ['to', '1'],            [],
      ['to', '2'],            [('002_bar', 'up')],
      ['upto', '2'],          [('002_bar', 'up')],
      ['upto', '002_bar'],    [('002_bar', 'up')],
      ['upto', '4'],          [('002_bar', 'up')],
      ['upto', '004_foo'],    NoSuchMigrationError,
      ['upto', '5'],          AmbiguousMigrationNameError,
      ['upto', '005_hello'],  [('002_bar', 'up'), ('005_hello', 'up')],
      ['upto', '005_omg'],    [('002_bar', 'up'), ('005_hello', 'up'), ('005_omg', 'up')],
      ['downto', '1'],        [],
      ['downto', '2'],        [],
    )

    si.mark_as_applied('002_bar')
    si.mark_as_applied('005_hello')
    si.mark_as_applied('005_omg')
    
    self.assert_plans(si,
      ['apply', '1'],         [],
      ['apply', '001_foo'],   [],
      ['apply', '1', '2'],    [],
      ['unapply', '001_foo'], [('001_foo', 'down')],
      ['unapply', '1', '2'],  [('001_foo', 'down'), ('002_bar', 'down')],

      ['all'],                [],
      ['up'],                 [],
      ['down'],               [('005_omg', 'down')],

      ['to', '1'],            [('005_omg', 'down'), ('005_hello', 'down'), ('002_bar', 'down')],
      ['to', '2'],            [('005_omg', 'down'), ('005_hello', 'down')],
      ['upto', '2'],          [],
      ['upto', '002_bar'],    [],
      ['upto', '4'],          [],
      ['upto', '004_foo'],    NoSuchMigrationError,
      ['upto', '5'],          AmbiguousMigrationNameError,
      ['upto', '005_hello'],  [],
      ['upto', '005_omg'],    [],
      ['downto', '1'],        [('005_omg', 'down'), ('005_hello', 'down'), ('002_bar', 'down')],
      ['downto', '2'],        [('005_omg', 'down'), ('005_hello', 'down')],
    )
Example #15
0
  def test_applying_and_unapplying(self):
    def assert_applied(f, b, h):
      self.assert_equal([f, b, h], [si.is_applied('001_foo'), si.is_applied('002_bar'), si.is_applied('005_hello')])
  
    si = MigrationState()
    self.cursor.execute(create_new)
    
    assert_applied(False, False, False)
    
    si.mark_as_applied('001_foo')
    assert_applied(True, False, False)

    si.mark_as_applied('005_hello')
    assert_applied(True, False, True)

    si.mark_as_applied('005_hello')
    assert_applied(True, False, True)

    si.mark_as_unapplied('002_bar')
    assert_applied(True, False, True)

    si.mark_as_unapplied('005_hello')
    assert_applied(True, False, False)

    si.mark_as_applied('002_bar')
    assert_applied(True, True, False)
Example #16
0
    def test_when_doing_something_then_loggged(self):
        db = MigrationDb(directory=self.mock_migrations_dir)
        db.warn = WarningsMocker()
        si = MigrationState(migration_db=db, dev=True)
        si.init()

        si.apply('001_foo')
        si.mark_as_unapplied('001_foo')
        si.apply('001_foo')
        si.mark_as_applied('005_omg')
        si.unapply('001_foo')

        self.assert_equal([
            ("apply", "001_foo", "success"),
            ("mark_as_unapplied", "001_foo", "success"),
            ("apply", "001_foo", "success"),
            ("mark_as_applied", "005_omg", "success"),
            ("unapply", "001_foo", "success"),
        ], [row[:3] for row in get_log()])
        self.assert_equal(True, isinstance(get_log()[0][3], datetime))
Example #17
0
    def handle(self, *args, **options):
        try:
            migrations_dir = settings.DMIGRATIONS_DIR
        except AttributeError:
            print "You need to add DMIGRATIONS_DIR to your settings"
            return
        migration_db = MigrationDb(directory = migrations_dir)
        migration_state = MigrationState(
            migration_db = migration_db, dev = options.get('dev')
        )
        verbosity = int(options.get('verbosity', 1))

        if not args or args[0] == 'help':
            # TODO: Do this without calling os.system
            os.system('python manage.py help dmigrate')
            return

        elif args[0] in 'all up down upto downto to apply unapply'.split():
            migration_state.init()
            for (migration_name, action) in migration_state.plan(*args):
                migration = migration_db.load_migration_object(migration_name)
                if action == 'up':
                    if verbosity >= 1:
                        print "Applying migration %s" % migration.name
                    if not options.get('print_plan'):
                        migration_state.apply(migration_name)
                else:
                    if verbosity >= 1:
                        print "Unapplying migration %s" % migration.name
                    if not options.get('print_plan'):
                        migration_state.unapply(migration_name)

        elif args[0] == 'mark_as_applied':
            migration_state.init()
            for name in args[1:]:
                resolved_name = migration_state.resolve_name(name)
                if resolved_name == None:
                    raise NoSuchMigrationError(name)
                migration_state.mark_as_applied(resolved_name)

        elif args[0] == 'mark_as_unapplied':
            migration_state.init()
            for name in args[1:]:
                resolved_name = migration_state.resolve_name(name)
                if resolved_name == None:
                    raise NoSuchMigrationError(name)
                migration_state.mark_as_unapplied(resolved_name)

        elif args[0] == 'list':
            migration_state.init()
            for migration_name in migration_db.list():
                if migration_state.is_applied(migration_name):
                   print "* [+] %s" % migration_name
                else:
                   print "* [ ] %s" % migration_name
            migrations_not_in_db = migration_state.applied_but_not_in_db()
            if migrations_not_in_db:
                print "These migrations are marked as applied but cannot " \
                    "be found:"
                for migration_name in migrations_not_in_db:
                    print "* [?] %s" % migration_name
            return

        elif args[0] == 'init':
            migration_state.init()

        elif args[0] == 'cat':
            for name in args[1:]:
                print open(
                    migration_db.resolve_migration_path(name), 'r'
                ).read()
            return

        else:
            raise CommandError(
                'Argument should be one of: list, help, up, down, all, init, '
                'apply, unapply, to, downto, upto, mark_as_applied, '
                'mark_as_unapplied'
            )

        # Ensure Django permissions and content_types have been created
        # NOTE: Don't run if django_content_type doesn't exist yet.
        if table_present('django_content_type'):
            from django.contrib.auth.management import create_permissions
            from django.db import models
            for app in models.get_apps():
                if verbosity >= 1:
                    create_permissions(app, set(), 2)
                else:
                    create_permissions(app, set(), 1)
  def test_plan_with_dev(self):
    # NOTE: si.mark_as_applied modifies global state, not si (MigrationState) object.
    #       There is only one meaningful MigrationState object per database,
    #       so it's an almost-singleton unless we support multiple databases at the same time.
    #       This makes testing quite ugly.
    db = MigrationDb(migrations = ['001_foo', '002_DEV_bar', '005_omg', '006_DEV_hello'])

    si = MigrationState(migration_db=db)
    si.init()
    self.assert_plans(si,
      ['up'],        [('001_foo', 'up')],
      ['upto', '5'], [('001_foo', 'up'), ('005_omg', 'up')],
      ['upto', '6'], [('001_foo', 'up'), ('005_omg', 'up')],
      ['all'],       [('001_foo', 'up'), ('005_omg', 'up')],
    )

    si = MigrationState(migration_db=db, dev=True)
    si.init()
    self.assert_plans(si,
      ['up'],        [('001_foo', 'up')],
      ['upto', '5'], [('001_foo', 'up'), ('002_DEV_bar', 'up'), ('005_omg', 'up')],
      ['upto', '6'], [('001_foo', 'up'), ('002_DEV_bar', 'up'), ('005_omg', 'up'), ('006_DEV_hello', 'up')],
      ['all'],       [('001_foo', 'up'), ('002_DEV_bar', 'up'), ('005_omg', 'up'), ('006_DEV_hello', 'up')],
    )

    si.mark_as_applied('001_foo')

    si = MigrationState(migration_db=db)
    si.init()
    self.assert_plans(si,
      ['up'],        [('005_omg', 'up')],
      ['upto', '5'], [('005_omg', 'up')],
      ['upto', '6'], [('005_omg', 'up')],
      ['all'],       [('005_omg', 'up')],
    )

    si = MigrationState(migration_db=db, dev=True)
    si.init()
    self.assert_plans(si,
      ['up'],        [('002_DEV_bar', 'up')],
      ['upto', '5'], [('002_DEV_bar', 'up'), ('005_omg', 'up')],
      ['upto', '6'], [('002_DEV_bar', 'up'), ('005_omg', 'up'), ('006_DEV_hello', 'up')],
      ['all'],       [('002_DEV_bar', 'up'), ('005_omg', 'up'), ('006_DEV_hello', 'up')],
    )

    si.mark_as_applied('002_DEV_bar')

    si = MigrationState(migration_db=db)
    si.init()
    self.assert_plans(si,
      ['up'],        [('005_omg', 'up')],
      ['upto', '5'], [('005_omg', 'up')],
      ['upto', '6'], [('005_omg', 'up')],
      ['all'],       [('005_omg', 'up')],
      ['down'],      [('001_foo', 'down')], # Is it better to always assume --dev on down ?
    )

    si = MigrationState(migration_db=db, dev=True)
    si.init()
    self.assert_plans(si,
      ['up'],        [('005_omg', 'up')],
      ['upto', '5'], [('005_omg', 'up')],
      ['upto', '6'], [('005_omg', 'up'), ('006_DEV_hello', 'up')],
      ['all'],       [('005_omg', 'up'), ('006_DEV_hello', 'up')],
      ['down'],      [('002_DEV_bar', 'down')],
    )