Example #1
0
def create_project_sig(database):
    """
    Create a dictionary representation of the apps in a given project.
    """
    proj_sig = {
        '__version__': 1,
    }

    for app in get_apps():
        proj_sig[app.__name__.split('.')[-2]] = create_app_sig(app, database)

    return proj_sig
Example #2
0
def create_project_sig(database):
    """
    Create a dictionary representation of the apps in a given project.
    """
    proj_sig = {
        '__version__': 1,
    }

    for app in get_apps():
        proj_sig[get_app_label(app)] = create_app_sig(app, database)

    return proj_sig
Example #3
0
def _on_app_models_updated(app, using=DEFAULT_DB_ALIAS, **kwargs):
    """Handler for when an app's models were updated.

    This is called in response to a syncdb or migrate operation for an app.
    The very first time this is called for Django Evolution's app, this will
    set up the current project version to contain the full database signature,
    and to populate the list of evolutions with all currently-registered ones.

    This is only done when we're not actively evolving the database. That
    means it will only be called if we're running unit tests or in reaction
    to some other process that emits the signals (such as the flush management
    command).

    Args:
        app (module):
            The app models module that was updated.

        using (str, optional):
            The database being updated.

        **kwargs (dict):
            Additional keyword arguments provided by the signal handler for
            the syncdb or migrate operation.
    """
    global _django_evolution_app

    if _django_evolution_app is None:
        _django_evolution_app = get_app('django_evolution')

    if (_evolve_lock > 0 or
        app is not _django_evolution_app or
        Version.objects.using(using).exists()):
        return

    evolver = Evolver(database_name=using)

    version = evolver.version
    version.signature = evolver.target_project_sig
    version.save(using=using)

    evolutions = []

    for app in get_apps():
        app_label = get_app_label(app)

        evolutions += [
            Evolution(app_label=app_label,
                      label=evolution_label,
                      version=version)
            for evolution_label in get_evolution_sequence(app)
        ]

    Evolution.objects.using(using).bulk_create(evolutions)
Example #4
0
    def handle(self, **options):
        """Handle the command.

        Args:
            **options (dict, unused):
                Options parsed on the command line. For this command, no
                options are available.
        """
        models = []

        for app in get_apps():
            models.extend(get_models(app))

        OBJECT_LIMIT = 150

        serializer = serializers.get_serializer('json')()

        totalobjs = 0

        for model in models:
            totalobjs += model.objects.count()

        prev_pct = -1
        i = 0

        self.stderr.write(_('Dump the database. This may take a while...\n'))

        self.stdout.write('# dbdump v1 - %s objects' % totalobjs)

        for model in models:
            count = model.objects.count()
            j = 0

            while j < count:
                for obj in model.objects.all()[j:j + OBJECT_LIMIT].iterator():
                    value = serializer.serialize([obj])

                    if value != '[]':
                        self.stdout.write(value[1:-1])  # Skip the "[" and "]"

                    i += 1
                    pct = i * 100 / totalobjs

                    if pct != prev_pct:
                        self.stderr.write('  [%s%%]\r' % pct)
                        self.stderr.flush()
                        prev_pct = pct

                j += OBJECT_LIMIT

        self.stderr.write('\nDone.\n')
    def handle(self, *app_labels, **options):
        if not app_labels:
            app_labels = [get_app_label(app) for app in get_apps()]

        for app_label in app_labels:
            evolutions = list(Evolution.objects.filter(app_label=app_label))

            if evolutions:
                print "Applied evolutions for '%s':" % app_label

                for evolution in evolutions:
                    print '    %s' % evolution.label

                print
    def test_queue_evolve_all_apps(self):
        """Testing Evolver.queue_evolve_all_apps"""
        evolver = Evolver()
        evolver.queue_evolve_all_apps()

        apps = get_apps()
        tasks = list(evolver.tasks)

        self.assertGreater(len(apps), 0)
        self.assertEqual(len(tasks), len(apps))

        for app, task in zip(apps, tasks):
            self.assertIsInstance(task, EvolveAppTask)
            self.assertIs(task.app, app)
    def handle(self, *app_labels, **options):
        if not app_labels:
            app_labels = [get_app_label(app) for app in get_apps()]

        for app_label in app_labels:
            evolutions = list(Evolution.objects.filter(app_label=app_label))

            if evolutions:
                print("Applied evolutions for '%s':" % app_label)

                for evolution in evolutions:
                    print('    %s' % evolution.label)

                print()
    def handle(self, *app_labels, **options):
        if not app_labels:
            app_labels = [app.__name__.split('.')[-2] for app in get_apps()]

        for app_label in app_labels:
            evolutions = list(Evolution.objects.filter(app_label=app_label))

            if evolutions:
                print "Applied evolutions for '%s':" % app_label

                for evolution in evolutions:
                    print '    %s' % evolution.label

                print
    def test_queue_evolve_all_apps(self):
        """Testing Evolver.queue_evolve_all_apps"""
        evolver = Evolver()
        evolver.queue_evolve_all_apps()

        apps = get_apps()
        tasks = list(evolver.tasks)

        self.assertGreater(len(apps), 0)
        self.assertEqual(len(tasks), len(apps))

        for app, task in zip(apps, tasks):
            self.assertIsInstance(task, EvolveAppTask)
            self.assertIs(task.app, app)
Example #10
0
    def queue_evolve_all_apps(self):
        """Queue an evolution of all registered Django apps.

        This cannot be used if :py:meth:`queue_evolve_app` is also being used.

        Raises:
            django_evolution.errors.EvolutionTaskAlreadyQueuedError:
                An evolution for an app was already queued.

            django_evolution.errors.QueueEvolverTaskError:
                Error queueing a non-duplicate task. Tasks may have already
                been prepared and finalized.
        """
        for app in get_apps():
            self.queue_evolve_app(app)
Example #11
0
def evolution(app, created_models, verbosity=1, **kwargs):
    """
    A hook into syncdb's post_syncdb signal, that is used to notify the user
    if a model evolution is necessary.
    """
    default_db = DEFAULT_DB_ALIAS

    db = kwargs.get('db', default_db)
    proj_sig = create_project_sig(db)
    signature = pickle.dumps(proj_sig)

    using_args = {
        'using': db,
    }

    try:
        latest_version = \
            django_evolution.Version.objects.current_version(using=db)
    except django_evolution.Version.DoesNotExist:
        # We need to create a baseline version.
        if verbosity > 0:
            print "Installing baseline version"

        latest_version = django_evolution.Version(signature=signature)
        latest_version.save(**using_args)

        for a in get_apps():
            install_baseline(a, latest_version, using_args, verbosity)

    unapplied = get_unapplied_evolutions(app, db)

    if unapplied:
        print style.NOTICE('There are unapplied evolutions for %s.'
                           % app.__name__.split('.')[-2])

    # Evolutions are checked over the entire project, so we only need to check
    # once. We do this check when Django Evolutions itself is synchronized.
    if app == django_evolution:
        old_proj_sig = pickle.loads(str(latest_version.signature))

        # If any models or apps have been added, a baseline must be set
        # for those new models
        changed = False
        new_apps = []

        for app_name, new_app_sig in proj_sig.items():
            if app_name == '__version__':
                # Ignore the __version__ tag
                continue

            old_app_sig = old_proj_sig.get(app_name, None)

            if old_app_sig is None:
                # App has been added
                old_proj_sig[app_name] = proj_sig[app_name]
                new_apps.append(app_name)
                changed = True
            else:
                for model_name, new_model_sig in new_app_sig.items():
                    old_model_sig = old_app_sig.get(model_name, None)

                    if old_model_sig is None:
                        # Model has been added
                        old_proj_sig[app_name][model_name] = \
                            proj_sig[app_name][model_name]
                        changed = True

        if changed:
            if verbosity > 0:
                print "Adding baseline version for new models"

            latest_version = \
                django_evolution.Version(signature=pickle.dumps(old_proj_sig))
            latest_version.save(**using_args)

            for app_name in new_apps:
                app = get_app(app_name, True)

                if app:
                    install_baseline(app, latest_version, using_args,
                                     verbosity)

        # TODO: Model introspection step goes here.
        # # If the current database state doesn't match the last
        # # saved signature (as reported by latest_version),
        # # then we need to update the Evolution table.
        # actual_sig = introspect_project_sig()
        # acutal = pickle.dumps(actual_sig)
        # if actual != latest_version.signature:
        #     nudge = Version(signature=actual)
        #     nudge.save()
        #     latest_version = nudge

        diff = Diff(old_proj_sig, proj_sig)

        if not diff.is_empty():
            print style.NOTICE(
                'Project signature has changed - an evolution is required')

            if verbosity > 1:
                old_proj_sig = pickle.loads(str(latest_version.signature))
                print diff
Example #12
0
def evolution(app, created_models, verbosity=1, **kwargs):
    """
    A hook into syncdb's post_syncdb signal, that is used to notify the user
    if a model evolution is necessary.
    """
    default_db = DEFAULT_DB_ALIAS

    db = kwargs.get('db', default_db)
    proj_sig = create_project_sig(db)
    signature = pickle.dumps(proj_sig)

    using_args = {
        'using': db,
    }

    try:
        latest_version = \
            django_evolution.Version.objects.current_version(using=db)
    except django_evolution.Version.DoesNotExist:
        # We need to create a baseline version.
        if verbosity > 0:
            print "Installing baseline version"

        latest_version = django_evolution.Version(signature=signature)
        latest_version.save(**using_args)

        for a in get_apps():
            install_baseline(a, latest_version, using_args, verbosity)

    unapplied = get_unapplied_evolutions(app, db)

    if unapplied:
        print style.NOTICE('There are unapplied evolutions for %s.'
                           % get_app_label(app))

    # Evolutions are checked over the entire project, so we only need to check
    # once. We do this check when Django Evolutions itself is synchronized.
    if app == django_evolution:
        old_proj_sig = pickle.loads(str(latest_version.signature))

        # If any models or apps have been added, a baseline must be set
        # for those new models
        changed = False
        new_apps = []

        for app_name, new_app_sig in proj_sig.items():
            if app_name == '__version__':
                # Ignore the __version__ tag
                continue

            old_app_sig = old_proj_sig.get(app_name, None)

            if old_app_sig is None:
                # App has been added
                old_proj_sig[app_name] = proj_sig[app_name]
                new_apps.append(app_name)
                changed = True
            else:
                for model_name, new_model_sig in new_app_sig.items():
                    old_model_sig = old_app_sig.get(model_name, None)

                    if old_model_sig is None:
                        # Model has been added
                        old_proj_sig[app_name][model_name] = \
                            proj_sig[app_name][model_name]
                        changed = True

        if changed:
            if verbosity > 0:
                print "Adding baseline version for new models"

            latest_version = \
                django_evolution.Version(signature=pickle.dumps(old_proj_sig))
            latest_version.save(**using_args)

            for app_name in new_apps:
                app = get_app(app_name, True)

                if app:
                    install_baseline(app, latest_version, using_args,
                                     verbosity)

        # TODO: Model introspection step goes here.
        # # If the current database state doesn't match the last
        # # saved signature (as reported by latest_version),
        # # then we need to update the Evolution table.
        # actual_sig = introspect_project_sig()
        # acutal = pickle.dumps(actual_sig)
        # if actual != latest_version.signature:
        #     nudge = Version(signature=actual)
        #     nudge.save()
        #     latest_version = nudge

        diff = Diff(old_proj_sig, proj_sig)

        if not diff.is_empty():
            print style.NOTICE(
                'Project signature has changed - an evolution is required')

            if verbosity > 1:
                old_proj_sig = pickle.loads(str(latest_version.signature))
                print diff
def _on_app_models_updated(app, verbosity=1, using=DEFAULT_DB_ALIAS, **kwargs):
    """Handler for when an app's models were updated.

    This is called in response to a syncdb or migrate operation for an app.
    It will install baselines for any new models, record the changes in the
    evolution history, and notify the user if any of the changes require an
    evolution.

    Args:
        app (module):
            The app models module that was updated.

        verbosity (int, optional):
            The verbosity used to control output. This will have been provided
            by the syncdb or migrate command.

        using (str, optional):
            The database being updated.

        **kwargs (dict):
            Additional keyword arguments provided by the signal handler for
            the syncdb or migrate operation.
    """
    project_sig = ProjectSignature.from_database(using)

    try:
        latest_version = Version.objects.current_version(using=using)
    except Version.DoesNotExist:
        # We need to create a baseline version.
        if verbosity > 0:
            print("Installing baseline version")

        latest_version = Version(signature=project_sig)
        latest_version.save(using=using)

        for a in get_apps():
            _install_baseline(app=a,
                              latest_version=latest_version,
                              using=using,
                              verbosity=verbosity)

    unapplied = get_unapplied_evolutions(app, using)

    if unapplied:
        print(
            style.NOTICE('There are unapplied evolutions for %s.' %
                         get_app_label(app)))

    # Evolutions are checked over the entire project, so we only need to check
    # once. We do this check when Django Evolutions itself is synchronized.

    if app is get_app('django_evolution'):
        old_project_sig = latest_version.signature

        # If any models or apps have been added, a baseline must be set
        # for those new models
        changed = False
        new_apps = []

        for new_app_sig in project_sig.app_sigs:
            app_id = new_app_sig.app_id
            old_app_sig = old_project_sig.get_app_sig(app_id)

            if old_app_sig is None:
                # App has been added
                old_project_sig.add_app_sig(new_app_sig.clone())
                new_apps.append(app_id)
                changed = True
            else:
                for new_model_sig in new_app_sig.model_sigs:
                    model_name = new_model_sig.model_name

                    old_model_sig = old_app_sig.get_model_sig(model_name)

                    if old_model_sig is None:
                        # Model has been added
                        old_app_sig.add_model_sig(
                            project_sig.get_app_sig(app_id).get_model_sig(
                                model_name).clone())
                        changed = True

        if changed:
            if verbosity > 0:
                print("Adding baseline version for new models")

            latest_version = Version(signature=old_project_sig)
            latest_version.save(using=using)

            for app_name in new_apps:
                app = get_app(app_name, True)

                if app:
                    _install_baseline(app=app,
                                      latest_version=latest_version,
                                      using=using,
                                      verbosity=verbosity)

        # TODO: Model introspection step goes here.
        # # If the current database state doesn't match the last
        # # saved signature (as reported by latest_version),
        # # then we need to update the Evolution table.
        # actual_sig = introspect_project_sig()
        # acutal = pickle.dumps(actual_sig)
        # if actual != latest_version.signature:
        #     nudge = Version(signature=actual)
        #     nudge.save()
        #     latest_version = nudge

        diff = Diff(old_project_sig, project_sig)

        if not diff.is_empty():
            print(
                style.NOTICE(
                    'Project signature has changed - an evolution is required')
            )

            if verbosity > 1:
                print(diff)
Example #14
0
def _on_app_models_updated(app, verbosity=1, using=DEFAULT_DB_ALIAS, **kwargs):
    """Handler for when an app's models were updated.

    This is called in response to a syncdb or migrate operation for an app.
    It will install baselines for any new models, record the changes in the
    evolution history, and notify the user if any of the changes require an
    evolution.

    Args:
        app (module):
            The app models module that was updated.

        verbosity (int, optional):
            The verbosity used to control output. This will have been provided
            by the syncdb or migrate command.

        using (str, optional):
            The database being updated.

        **kwargs (dict):
            Additional keyword arguments provided by the signal handler for
            the syncdb or migrate operation.
    """
    project_sig = ProjectSignature.from_database(using)

    try:
        latest_version = Version.objects.current_version(using=using)
    except Version.DoesNotExist:
        # We need to create a baseline version.
        if verbosity > 0:
            print("Installing baseline version")

        latest_version = Version(signature=project_sig)
        latest_version.save(using=using)

        for a in get_apps():
            _install_baseline(app=a,
                              latest_version=latest_version,
                              using=using,
                              verbosity=verbosity)

    unapplied = get_unapplied_evolutions(app, using)

    if unapplied:
        print(style.NOTICE('There are unapplied evolutions for %s.'
                           % get_app_label(app)))

    # Evolutions are checked over the entire project, so we only need to check
    # once. We do this check when Django Evolutions itself is synchronized.

    if app is get_app('django_evolution'):
        old_project_sig = latest_version.signature

        # If any models or apps have been added, a baseline must be set
        # for those new models
        changed = False
        new_apps = []

        for new_app_sig in project_sig.app_sigs:
            app_id = new_app_sig.app_id
            old_app_sig = old_project_sig.get_app_sig(app_id)

            if old_app_sig is None:
                # App has been added
                old_project_sig.add_app_sig(new_app_sig.clone())
                new_apps.append(app_id)
                changed = True
            else:
                for new_model_sig in new_app_sig.model_sigs:
                    model_name = new_model_sig.model_name

                    old_model_sig = old_app_sig.get_model_sig(model_name)

                    if old_model_sig is None:
                        # Model has been added
                        old_app_sig.add_model_sig(
                            project_sig
                            .get_app_sig(app_id)
                            .get_model_sig(model_name)
                            .clone())
                        changed = True

        if changed:
            if verbosity > 0:
                print("Adding baseline version for new models")

            latest_version = Version(signature=old_project_sig)
            latest_version.save(using=using)

            for app_name in new_apps:
                app = get_app(app_name, True)

                if app:
                    _install_baseline(app=app,
                                      latest_version=latest_version,
                                      using=using,
                                      verbosity=verbosity)

        # TODO: Model introspection step goes here.
        # # If the current database state doesn't match the last
        # # saved signature (as reported by latest_version),
        # # then we need to update the Evolution table.
        # actual_sig = introspect_project_sig()
        # acutal = pickle.dumps(actual_sig)
        # if actual != latest_version.signature:
        #     nudge = Version(signature=actual)
        #     nudge.save()
        #     latest_version = nudge

        diff = Diff(old_project_sig, project_sig)

        if not diff.is_empty():
            print(style.NOTICE(
                'Project signature has changed - an evolution is required'))

            if verbosity > 1:
                print(diff)
Example #15
0
    def handle(self, *args, **options):
        """Handle the command.

        Args:
            **options (dict, unused):
                Options parsed on the command line. For this command, no
                options are available.

        Raises:
            django.core.management.CommandError:
                There was an error with arguments or disabling the extension.
        """
        if len(args) != 1:
            raise CommandError(
                _('You must specify a filename on the command line.'))

        filename = args[0]

        if not os.path.exists(filename):
            raise CommandError(_('%s does not exist.') % filename)

        try:
            importlib.import_module('django_reset')
        except ImportError:
            raise CommandError(
                _('Before using this command, you need to '
                  'install the "django-reset" package'))

        confirm = input("""
This will wipe out your existing database prior to loading. It is highly
recommended that you have a full SQL database dump in case things go wrong.

You should only use this if you're migrating from one type of database to
another, with the same version of Review Board on each.

Are you sure you want to continue?"

Type 'yes' to continue, or 'no' to cancel: """)

        if confirm != 'yes':
            return

        apps = [app.__name__.split('.')[-2] for app in get_apps()]

        os.system('./reviewboard/manage.py reset --noinput %s' %
                  ' '.join(apps))

        transaction_setup = False

        try:
            with open(filename, 'r') as f:
                line = f.readline()

                m = re.match(r'^# dbdump v(\d+) - (\d+) objects$', line)

                if not m:
                    raise CommandError(_('Unknown dump format'))

                version = int(m.group(1))
                totalobjs = int(m.group(2))
                i = 0
                prev_pct = -1

                if version != 1:
                    raise CommandError(_('Unknown dump version'))

                transaction.commit_unless_managed()
                transaction.enter_transaction_management()
                transaction.managed(True)
                transaction_setup = True

                self.stdout.write(
                    _('Importing new style dump format (v%s)') % version)

                for line in f:
                    if line[0] == '{':
                        for obj in serializers.deserialize(
                                'json', '[%s]' % line):
                            try:
                                obj.save()
                            except Exception as e:
                                self.stderr.write(_('Error: %s') % e)
                                self.stderr.write(
                                    _('Line %s: "%s"') % (i, line))
                    elif line[0] != '#':
                        self.stderr.write(_('Junk data on line %s') % i)

                    db.reset_queries()

                    i += 1
                    pct = (i * 100 / totalobjs)

                    if pct != prev_pct:
                        self.stdout.write('  [%s%%]\r' % pct)
                        self.stdout.flush()
                        prev_pct = pct

            transaction.commit()
            transaction.leave_transaction_management()
        except Exception as e:
            if transaction_setup:
                transaction.rollback()
                transaction.leave_transaction_management()

            raise CommandError(
                _('Problem installing "%s": %s') % (filename, e))

        self.stdout.write(_('\nDone.'))