Exemplo n.º 1
0
 def suggest_name(cls, ops):
     """
     Given a set of operations, suggests a name for the change
     they might represent. Names are not guaranteed to be unique,
     but we put some effort in to the fallback name to avoid VCS conflicts
     if we can.
     """
     return 'auto_%s' % get_migration_name_timestamp()
Exemplo n.º 2
0
 def suggest_name(self):
     """
     Suggest a name for the operations this migration might represent. Names
     are not guaranteed to be unique, but put some effort into the fallback
     name to avoid VCS conflicts if possible.
     """
     name = None
     if len(self.operations) == 1:
         name = self.operations[0].migration_name_fragment
     elif (
         len(self.operations) > 1 and
         all(isinstance(o, operations.CreateModel) for o in self.operations)
     ):
         name = '_'.join(sorted(o.migration_name_fragment for o in self.operations))
     if name is None:
         name = 'initial' if self.initial else 'auto_%s' % get_migration_name_timestamp()
     return name
Exemplo n.º 3
0
    def suggest_name(self):
        """
        Suggest a name for the operations this migration might represent. Names
        are not guaranteed to be unique, but put some effort into the fallback
        name to avoid VCS conflicts if possible.
        """
        if self.initial:
            return 'initial'

        raw_fragments = [op.migration_name_fragment for op in self.operations]
        fragments = [name for name in raw_fragments if name]

        if not fragments or len(fragments) != len(self.operations):
            return 'auto_%s' % get_migration_name_timestamp()

        name = fragments[0]
        for fragment in fragments[1:]:
            new_name = f'{name}_{fragment}'
            if len(new_name) > 52:
                name = f'{name}_and_more'
                break
            name = new_name
        return name
Exemplo n.º 4
0
    def handle_merge(self, loader, conflicts):
        """
        Handles merging together conflicted migrations interactively,
        if it's safe; otherwise, advises on how to fix it.
        """
        if self.interactive:
            questioner = InteractiveMigrationQuestioner()
        else:
            questioner = MigrationQuestioner(defaults={'ask_merge': True})

        for app_label, migration_names in conflicts.items():
            # Grab out the migrations in question, and work out their
            # common ancestor.
            merge_migrations = []
            for migration_name in migration_names:
                migration = loader.get_migration(app_label, migration_name)
                migration.ancestry = [
                    mig for mig in loader.graph.forwards_plan((app_label, migration_name))
                    if mig[0] == migration.app_label
                ]
                merge_migrations.append(migration)

            def all_items_equal(seq):
                return all(item == seq[0] for item in seq[1:])

            merge_migrations_generations = zip(*(m.ancestry for m in merge_migrations))
            common_ancestor_count = sum(1 for common_ancestor_generation
                                        in takewhile(all_items_equal, merge_migrations_generations))
            if not common_ancestor_count:
                raise ValueError("Could not find common ancestor of %s" % migration_names)
            # Now work out the operations along each divergent branch
            for migration in merge_migrations:
                migration.branch = migration.ancestry[common_ancestor_count:]
                migrations_ops = (loader.get_migration(node_app, node_name).operations
                                  for node_app, node_name in migration.branch)
                migration.merged_operations = sum(migrations_ops, [])
            # In future, this could use some of the Optimizer code
            # (can_optimize_through) to automatically see if they're
            # mergeable. For now, we always just prompt the user.
            if self.verbosity > 0:
                self.stdout.write(self.style.MIGRATE_HEADING("Merging %s" % app_label))
                for migration in merge_migrations:
                    self.stdout.write(self.style.MIGRATE_LABEL("  Branch %s" % migration.name))
                    for operation in migration.merged_operations:
                        self.stdout.write("    - %s\n" % operation.describe())
            if questioner.ask_merge(app_label):
                # If they still want to merge it, then write out an empty
                # file depending on the migrations needing merging.
                numbers = [
                    MigrationAutodetector.parse_number(migration.name)
                    for migration in merge_migrations
                ]
                try:
                    biggest_number = max(x for x in numbers if x is not None)
                except ValueError:
                    biggest_number = 1
                subclass = type("Migration", (Migration,), {
                    "dependencies": [(app_label, migration.name) for migration in merge_migrations],
                })
                migration_name = "%04i_%s" % (
                    biggest_number + 1,
                    self.migration_name or ("merge_%s" % get_migration_name_timestamp())
                )
                new_migration = subclass(migration_name, app_label)
                writer = MigrationWriter(new_migration)

                if not self.dry_run:
                    # Write the merge migrations file to the disk
                    with open(writer.path, "w", encoding='utf-8') as fh:
                        fh.write(writer.as_string())
                    if self.verbosity > 0:
                        self.stdout.write("\nCreated new merge migration %s" % writer.path)
                elif self.verbosity == 3:
                    # Alternatively, makemigrations --merge --dry-run --verbosity 3
                    # will output the merge migrations to stdout rather than saving
                    # the file to the disk.
                    self.stdout.write(self.style.MIGRATE_HEADING(
                        "Full merge migrations file '%s':" % writer.filename) + "\n"
                    )
                    self.stdout.write("%s\n" % writer.as_string())
Exemplo n.º 5
0
    def handle_merge(self, loader, conflicts):
        """
        Handles merging together conflicted migrations interactively,
        if it's safe; otherwise, advises on how to fix it.
        """
        if self.interactive:
            questioner = InteractiveMigrationQuestioner()
        else:
            questioner = MigrationQuestioner(defaults={"ask_merge": True})

        for app_label, migration_names in conflicts.items():
            # Grab out the migrations in question, and work out their
            # common ancestor.
            merge_migrations = []
            for migration_name in migration_names:
                migration = loader.get_migration(app_label, migration_name)
                migration.ancestry = [
                    mig for mig in loader.graph.forwards_plan((app_label,
                                                               migration_name))
                    if mig[0] == migration.app_label
                ]
                merge_migrations.append(migration)

            def all_items_equal(seq):
                return all(item == seq[0] for item in seq[1:])

            merge_migrations_generations = zip(*(m.ancestry
                                                 for m in merge_migrations))
            common_ancestor_count = sum(
                1 for common_ancestor_generation in takewhile(
                    all_items_equal, merge_migrations_generations))
            if not common_ancestor_count:
                raise ValueError("Could not find common ancestor of %s" %
                                 migration_names)
            # Now work out the operations along each divergent branch
            for migration in merge_migrations:
                migration.branch = migration.ancestry[common_ancestor_count:]
                migrations_ops = (loader.get_migration(node_app,
                                                       node_name).operations
                                  for node_app, node_name in migration.branch)
                migration.merged_operations = sum(migrations_ops, [])
            # In future, this could use some of the Optimizer code
            # (can_optimize_through) to automatically see if they're
            # mergeable. For now, we always just prompt the user.
            if self.verbosity > 0:
                self.stdout.write(
                    self.style.MIGRATE_HEADING("Merging %s" % app_label))
                for migration in merge_migrations:
                    self.stdout.write(
                        self.style.MIGRATE_LABEL("  Branch %s" %
                                                 migration.name))
                    for operation in migration.merged_operations:
                        self.stdout.write("    - %s" % operation.describe())
            if questioner.ask_merge(app_label):
                # If they still want to merge it, then write out an empty
                # file depending on the migrations needing merging.
                numbers = [
                    MigrationAutodetector.parse_number(migration.name)
                    for migration in merge_migrations
                ]
                try:
                    biggest_number = max(x for x in numbers if x is not None)
                except ValueError:
                    biggest_number = 1
                subclass = type(
                    "Migration",
                    (Migration, ),
                    {
                        "dependencies": [(app_label, migration.name)
                                         for migration in merge_migrations],
                    },
                )
                migration_name = "%04i_%s" % (
                    biggest_number + 1,
                    self.migration_name or
                    ("merge_%s" % get_migration_name_timestamp()),
                )
                new_migration = subclass(migration_name, app_label)
                writer = MigrationWriter(new_migration, self.include_header)

                if not self.dry_run:
                    # Write the merge migrations file to the disk
                    with open(writer.path, "w", encoding="utf-8") as fh:
                        fh.write(writer.as_string())
                    if self.verbosity > 0:
                        self.stdout.write("\nCreated new merge migration %s" %
                                          writer.path)
                elif self.verbosity == 3:
                    # Alternatively, makemigrations --merge --dry-run --verbosity 3
                    # will output the merge migrations to stdout rather than saving
                    # the file to the disk.
                    self.stdout.write(
                        self.style.MIGRATE_HEADING(
                            "Full merge migrations file '%s':" %
                            writer.filename))
                    self.stdout.write(writer.as_string())
Exemplo n.º 6
0
    def handle_merge(self, loader, conflicts):
        """
        Handles merging together conflicted changes interactively,
        if it's safe; otherwise, advises on how to fix it.
        """
        if self.interactive:
            questioner = InteractiveMigrationQuestioner()
        else:
            questioner = MigrationQuestioner(defaults={'ask_merge': True})

        for app_label, change_names in conflicts.items():
            # Grab out the changes in question, and work out their
            # common ancestor.
            merge_changes = []
            for change_name in change_names:
                change = loader.get_change(app_label, change_name)
                change.ancestry = [
                    mig for mig in loader.graph.forwards_plan((app_label, change_name))
                    if mig[0] == change.app_label
                ]
                merge_changes.append(change)

            def all_items_equal(seq):
                return all(item == seq[0] for item in seq[1:])

            merge_changes_generations = zip(*[m.ancestry for m in merge_changes])
            common_ancestor_count = sum(1 for common_ancestor_generation
                                        in takewhile(all_items_equal, merge_changes_generations))
            if not common_ancestor_count:
                raise ValueError('Could not find common ancestor of %s' % change_names)
            # Now work out the operations along each divergent branch
            for change in merge_changes:
                change.branch = change.ancestry[common_ancestor_count:]
                changes_ops = (loader.get_change(node_app, node_name).operations
                               for node_app, node_name in change.branch)
                change.merged_operations = sum(changes_ops, [])
            # In future, this could use some of the Optimizer code
            # (can_optimize_through) to automatically see if they're
            # mergeable. For now, we always just prompt the user.
            if self.verbosity > 0:
                self.stdout.write(self.style.MIGRATE_HEADING('Merging %s' % app_label))
                for change in merge_changes:
                    self.stdout.write(self.style.MIGRATE_LABEL('  Branch %s' % change.name))
                    for operation in change.merged_operations:
                        self.stdout.write('    - %s\n' % operation.describe())
            if questioner.ask_merge(app_label):
                # If they still want to merge it, then write out an empty
                # file depending on the changes needing merging.
                numbers = [
                    ChangeAutodetector.parse_number(change.name)
                    for change in merge_changes
                ]
                try:
                    biggest_number = max(x for x in numbers if x is not None)
                except ValueError:
                    biggest_number = 1
                subclass = type('Change', (Change, ), {
                    'dependencies': [(app_label, change.name) for change in merge_changes],
                })
                change_name = '%04i_%s' % (
                    biggest_number + 1,
                    self.change_name or ('merge_%s' % get_migration_name_timestamp())
                )
                new_change = subclass(change_name, app_label)
                writer = ChangeWriter(new_change)

                if not self.dry_run:
                    # Write the merge changes file to the disk
                    with io.open(writer.path, 'w', encoding='utf-8') as fh:
                        fh.write(writer.as_string())
                    if self.verbosity > 0:
                        self.stdout.write('\nCreated new merge change %s' % writer.path)
                elif self.verbosity == 3:
                    # Alternatively, makechanges --merge --dry-run --verbosity 3
                    # will output the merge changes to stdout rather than saving
                    # the file to the disk.
                    self.stdout.write(self.style.MIGRATE_HEADING(
                        "Full merge changes file '%s':" % writer.filename) + '\n'
                    )
                    self.stdout.write('%s\n' % writer.as_string())