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")
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")
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)
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
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)