Example #1
0
def prompt_save_config(config, path):
    # Offer to save the current configuration for future runs
    # Don't cache anything in batch mode (because we can't prompt to find the
    # user's preference).

    if utils.confirm("Save migration configuration to {}?\n"
                     "This is saved in plain text and "
                     "contains your database password.\n\n"
                     "Answering 'y' means you do not have to specify "
                     "the migration source or database connection "
                     "for future runs".format(path)):
        save_config(config, path)
Example #2
0
def upgrade_legacy_config(args, config, sources):

    for dir in reversed(sources):
        path = os.path.join(dir, LEGACY_CONFIG_FILENAME)
        if not os.path.isfile(path):
            continue

        legacy_config = read_config(path)

        def transfer_setting(oldname,
                             newname,
                             transform=None,
                             section="DEFAULT"):
            try:
                config.get(section, newname)
            except configparser.NoOptionError:
                try:
                    value = legacy_config.get(section, oldname)
                except configparser.NoOptionError:
                    pass
                else:
                    if transform:
                        value = transform(value)
                    config.set(section, newname, value)

        transfer_setting("dburi", "database")
        transfer_setting(
            "migration_table",
            "migration_table",
            lambda v: (default_migration_table if v == "None" else v),
        )

        config_path = args.config or CONFIG_FILENAME
        if not args.batch_mode:
            if utils.confirm(
                    "Move legacy configuration in {!r} to {!r}?".format(
                        path, config_path)):
                save_config(config, config_path)
                try:
                    if utils.confirm(
                            "Delete legacy configuration file {!r}".format(
                                path)):
                        os.unlink(path)
                except OSError:
                    logger.warn(
                        "Could not remove %r. Manually remove this file "
                        "to avoid future warnings",
                        path,
                    )
                return True
        else:
            logger.warn(
                "Found legacy configuration in %r. Run "
                "yoyo in interactive mode to update your "
                "configuration files",
                path,
            )

            try:
                args.database = args.database or legacy_config.get(
                    "DEFAULT", "dburi")
            except configparser.NoOptionError:
                pass
            try:
                args.migration_table = (args.migration_table
                                        or legacy_config.get(
                                            "DEFAULT", "migration_table"))
            except configparser.NoOptionError:
                pass

        return False
Example #3
0
def get_migrations(args, backend):

    sources = args.sources
    dburi = args.database

    if not sources:
        raise InvalidArgument("Please specify the migration source directory")

    migrations = read_migrations(*sources)

    if args.match:
        migrations = migrations.filter(
            lambda m: re.search(args.match, m.id) is not None
        )

    if args.revision:
        targets = [m for m in migrations if args.revision in m.id]
        if len(targets) == 0:
            raise InvalidArgument(
                "'{}' doesn't match any revisions.".format(args.revision)
            )
        if len(targets) > 1:
            raise InvalidArgument(
                "'{}' matches multiple revisions. "
                "Please specify one of {}.".format(
                    args.revision, ", ".join(m.id for m in targets)
                )
            )

        target = targets[0]

        # apply: apply target an all its dependencies
        if args.func in {mark, apply}:
            deps = ancestors(target, migrations)
            target_plus_deps = deps | {target}
            migrations = migrations.filter(lambda m: m in target_plus_deps)

        # rollback/reapply: rollback target and everything that depends on it
        else:
            deps = descendants(target, migrations)
            target_plus_deps = deps | {target}
            migrations = migrations.filter(lambda m: m in target_plus_deps)
    else:
        if args.func in {apply, mark}:
            migrations = backend.to_apply(migrations)

        elif args.func in {rollback, reapply, unmark}:
            migrations = backend.to_rollback(migrations)

    if not args.batch_mode and not args.revision:
        migrations = prompt_migrations(backend, migrations, args.command_name)

    if (
        args.batch_mode
        and not args.revision
        and not args.all
        and args.func is rollback
    ):
        if len(migrations) > 1:
            warnings.warn(
                "Only rolling back a single migration."
                "To roll back multiple migrations, "
                "either use interactive mode or use "
                "--revision or --all"
            )
            migrations = migrations[:1]

    if not args.batch_mode and migrations:
        print("")
        print(
            "Selected",
            utils.plural(len(migrations), "%d migration:", "%d migrations:"),
        )
        for m in migrations:
            print("  [{m.id}]".format(m=m))
        prompt = "{} {} to {}".format(
            args.command_name.title(),
            utils.plural(
                len(migrations), "this migration", "these %d migrations"
            ),
            dburi,
        )
        if not utils.confirm(prompt, default="y"):
            return migrations.replace([])
    return migrations