def _execute(self, cursor, stmt, out=None):
        """
        Execute the given statement. If rows are returned, output these in a
        tabulated format.
        """
        if out is None:
            out = stdout
        if isinstance(stmt, ustr):
            logger.debug(" - executing %r", stmt.encode("ascii", "replace"))
        else:
            logger.debug(" - executing %r", stmt)
        cursor.execute(stmt)
        if cursor.description:
            result = [[ustr(value) for value in row] for row in cursor.fetchall()]
            column_names = [desc[0] for desc in cursor.description]
            column_sizes = [len(c) for c in column_names]

            for row in result:
                for ix, value in enumerate(row):
                    if len(value) > column_sizes[ix]:
                        column_sizes[ix] = len(value)
            format = "|".join(" %%- %ds " % size for size in column_sizes)
            format += "\n"
            out.write(format % tuple(column_names))
            out.write("+".join("-" * (size + 2) for size in column_sizes) + "\n")
            for row in result:
                out.write(format % tuple(row))
            out.write(plural(len(result), "(%d row)", "(%d rows)") + "\n")
Beispiel #2
0
    def _execute(self, cursor, stmt, out=sys.stdout):
        """
        Execute the given statement. If rows are returned, output these in a
        tabulated format.
        """
        if isinstance(stmt, ustr):
            logger.debug(" - executing %r", stmt.encode('ascii', 'replace'))
        else:
            logger.debug(" - executing %r", stmt)
        cursor.execute(stmt)
        if cursor.description:
            result = [[ustr(value) for value in row]
                      for row in cursor.fetchall()]
            column_names = [desc[0] for desc in cursor.description]
            column_sizes = [len(c) for c in column_names]

            for row in result:
                for ix, value in enumerate(row):
                    if len(value) > column_sizes[ix]:
                        column_sizes[ix] = len(value)
            format = '|'.join(' %%- %ds ' % size for size in column_sizes)
            out.write(format % tuple(column_names) + "\n")
            out.write('+'.join('-' * (size + 2) for size in column_sizes)
                      + "\n")
            for row in result:
                out.write((format % tuple(row)).encode('utf8') + "\n")
            out.write(plural(len(result), '(%d row)', '(%d rows)') + "\n")
Beispiel #3
0
def main(argv=None):

    argparser = make_argparser()
    args = argparser.parse_args(argv)

    if args.verbosity_level:
        verbosity_level = args.verbosity_level
    else:
        verbosity_level = args.verbose
    verbosity_level = min(verbosity_level, max(verbosity_levels))
    verbosity_level = max(verbosity_level, min(verbosity_levels))
    configure_logging(verbosity_level)

    command = args.command
    migrations_dir = os.path.normpath(os.path.abspath(args.migrations_dir))
    dburi = args.database

    config_path = os.path.join(migrations_dir, '.yoyo-migrate')
    config = readconfig(config_path)

    if dburi is None and args.cache:
        try:
            logger.debug("Looking up connection string for %r", migrations_dir)
            dburi = config.get('DEFAULT', 'dburi')
        except (ValueError, NoSectionError, NoOptionError):
            pass

    if args.migration_table:
        migration_table = args.migration_table
    else:
        try:
            migration_table = config.get('DEFAULT', 'migration_table')
        except (ValueError, NoSectionError, NoOptionError):
            migration_table = None

    # Earlier versions had a bug where the migration_table could be set to the
    # string 'None'.
    if migration_table in (None, 'None'):
        migration_table = default_migration_table

    config.set('DEFAULT', 'migration_table', migration_table)

    if dburi is None:
        argparser.error("Please specify command, migrations directory and "
                        "database connection string arguments")

    if args.prompt_password:
        password = getpass('Password for %s: ' % dburi)
        scheme, username, _, host, port, database, db_params = parse_uri(dburi)
        dburi = unparse_uri(
            (scheme, username, password, host, port, database, db_params))

    # Cache the database this migration set is applied to so that subsequent
    # runs don't need the dburi argument. Don't cache anything in batch mode -
    # we can't prompt to find the user's preference.
    if args.cache and not args.batch:
        if not config.has_option('DEFAULT', 'dburi'):
            response = prompt(
                "Save connection string to %s for future migrations?\n"
                "This is saved in plain text and "
                "contains your database password." % (config_path, ), "yn")
            if response == 'y':
                config.set('DEFAULT', 'dburi', dburi)

        elif config.get('DEFAULT', 'dburi') != dburi:
            response = prompt(
                "Specified connection string differs from that saved in %s. "
                "Update saved connection string?" % (config_path, ), "yn")
            if response == 'y':
                config.set('DEFAULT', 'dburi', dburi)

        config.set('DEFAULT', 'migration_table', migration_table)
        saveconfig(config, config_path)

    conn, paramstyle = connect(dburi)

    migrations = read_migrations(conn,
                                 paramstyle,
                                 migrations_dir,
                                 migration_table=migration_table)

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

    if not args.all:
        if command in ['apply']:
            migrations = migrations.to_apply()

        elif command in ['reapply', 'rollback']:
            migrations = migrations.to_rollback()

    if not args.batch:
        migrations = prompt_migrations(conn, paramstyle, migrations, command)

    if not args.batch and migrations:
        if prompt(
                command.title() +
                plural(len(migrations), " %d migration", " %d migrations") +
                " to %s?" % dburi, "Yn") != 'y':
            return 0

    if command == 'reapply':
        migrations.rollback(args.force)
        migrations.apply(args.force)

    elif command == 'apply':
        migrations.apply(args.force)

    elif command == 'rollback':
        migrations.rollback(args.force)
Beispiel #4
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
Beispiel #5
0
def main(argv=None):

    argparser = make_argparser()
    args = argparser.parse_args(argv)

    if args.verbosity_level:
        verbosity_level = args.verbosity_level
    else:
        verbosity_level = args.verbose
    verbosity_level = min(verbosity_level, max(verbosity_levels))
    verbosity_level = max(verbosity_level, min(verbosity_levels))
    configure_logging(verbosity_level)

    command = args.command
    migrations_dir = os.path.normpath(os.path.abspath(args.migrations_dir))
    dburi = args.database

    config_path = os.path.join(migrations_dir, '.yoyo-migrate')
    config = readconfig(config_path)

    if dburi is None and args.cache:
        try:
            logger.debug("Looking up connection string for %r", migrations_dir)
            dburi = config.get('DEFAULT', 'dburi')
        except (ValueError, NoSectionError, NoOptionError):
            pass

    if args.migration_table:
        migration_table = args.migration_table
    else:
        try:
            migration_table = config.get('DEFAULT', 'migration_table')
        except (ValueError, NoSectionError, NoOptionError):
            migration_table = None

    # Earlier versions had a bug where the migration_table could be set to the
    # string 'None'.
    if migration_table in (None, 'None'):
        migration_table = default_migration_table

    config.set('DEFAULT', 'migration_table', migration_table)

    if dburi is None:
        argparser.error(
            "Please specify command, migrations directory and "
            "database connection string arguments"
        )

    if args.prompt_password:
        password = getpass('Password for %s: ' % dburi)
        scheme, username, _, host, port, database, db_params = parse_uri(dburi)
        dburi = unparse_uri((scheme, username, password, host, port, database, db_params))

    # Cache the database this migration set is applied to so that subsequent
    # runs don't need the dburi argument. Don't cache anything in batch mode -
    # we can't prompt to find the user's preference.
    if args.cache and not args.batch:
        if not config.has_option('DEFAULT', 'dburi'):
            response = prompt(
                "Save connection string to %s for future migrations?\n"
                "This is saved in plain text and "
                "contains your database password." % (config_path,),
                "yn"
            )
            if response == 'y':
                config.set('DEFAULT', 'dburi', dburi)

        elif config.get('DEFAULT', 'dburi') != dburi:
            response = prompt(
                "Specified connection string differs from that saved in %s. "
                "Update saved connection string?" % (config_path,),
                "yn"
            )
            if response == 'y':
                config.set('DEFAULT', 'dburi', dburi)

        config.set('DEFAULT', 'migration_table', migration_table)
        saveconfig(config, config_path)

    conn, paramstyle = connect(dburi)

    migrations = read_migrations(conn, paramstyle, migrations_dir,
                                 migration_table=migration_table)

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

    if not args.all:
        if command in ['apply']:
            migrations = migrations.to_apply()

        elif command in ['reapply', 'rollback']:
            migrations = migrations.to_rollback()

    if not args.batch:
        migrations = prompt_migrations(conn, paramstyle, migrations, command)

    if not args.batch and migrations:
        if prompt(command.title() +
                  plural(len(migrations), " %d migration", " %d migrations") +
                  " to %s?" % dburi, "Yn") != 'y':
            return 0

    if command == 'reapply':
        migrations.rollback(args.force)
        migrations.apply(args.force)

    elif command == 'apply':
        migrations.apply(args.force)

    elif command == 'rollback':
        migrations.rollback(args.force)