diff --git a/nashvegas/management/commands/comparedb.py b/nashvegas/management/commands/comparedb.py index 0605076..b15a717 100644 --- a/nashvegas/management/commands/comparedb.py +++ b/nashvegas/management/commands/comparedb.py @@ -15,13 +15,19 @@ class Command(BaseCommand): option_list = BaseCommand.option_list + ( - make_option("-n", "--name", action="store", dest="db_name", - help="The name of the database to hold the truth schema (defaults to _compare"), - make_option("-d", "--database", action="store", dest="database", - default=DEFAULT_DB_ALIAS, help="Nominates a database to synchronize. " - "Defaults to the \"default\" database."), + make_option("-n", "--name", + action="store", + dest="db_name", + help="The name of the database to hold the truth schema" + " (defaults to _compare"), + make_option("-d", "--database", + action="store", + dest="database", + default=DEFAULT_DB_ALIAS, + help="Nominates a database to synchronize. " + "Defaults to the \"default\" database."), ) - help = "Compares current database with the one that nashvegas will build from scratch." + help = "Checks for schema differences." def setup_database(self): command = NASHVEGAS.get("createdb", "createdb {dbname}") @@ -35,18 +41,18 @@ def handle(self, *args, **options): """ Compares current database with a migrations. - Creates a temporary database, applies all the migrations to it, and then - dumps the schema from both current and temporary, diffs them, then - report the diffs to the user. + Creates a temporary database, applies all the migrations to it, and + then dumps the schema from both current and temporary, diffs them, + then report the diffs to the user. """ self.db = options.get("database", DEFAULT_DB_ALIAS) self.current_name = connections[self.db].settings_dict["NAME"] self.compare_name = options.get("db_name") if not self.compare_name: self.compare_name = "%s_compare" % self.current_name - + command = NASHVEGAS.get("dumpdb", "pg_dump -s {dbname}") - + print "Getting schema for current database..." current_sql = Popen( command.format(dbname=self.current_name), diff --git a/nashvegas/management/commands/syncdb.py b/nashvegas/management/commands/syncdb.py index 65c1aa8..7c3d1d2 100644 --- a/nashvegas/management/commands/syncdb.py +++ b/nashvegas/management/commands/syncdb.py @@ -5,9 +5,11 @@ class Command(SyncDBCommand): def handle_noargs(self, **options): # Run migrations first - # {'load_initial_data': False, 'verbosity': 1, 'interactive': False, 'database': 'default'} - call_command("upgradedb", do_execute=True, database=options.get('database'), verbosity=options.get('verbosity')) - + call_command("upgradedb", + do_execute=True, + database=options.get('database'), + verbosity=options.get('verbosity')) + # Follow up with a syncdb on anything that wasnt included in migrations # (this catches things like test-only models) super(Command, self).handle_noargs(**options) diff --git a/nashvegas/management/commands/upgradedb.py b/nashvegas/management/commands/upgradedb.py index 847b842..93052f9 100644 --- a/nashvegas/management/commands/upgradedb.py +++ b/nashvegas/management/commands/upgradedb.py @@ -43,25 +43,44 @@ def __exit__(self, exc_type, exc_value, traceback): class Command(BaseCommand): option_list = BaseCommand.option_list + ( - make_option("-l", "--list", action="store_true", - dest="do_list", default=False, + make_option("-l", "--list", + action="store_true", + dest="do_list", + default=False, help="Enumerate the list of migrations to execute."), - make_option("-e", "--execute", action="store_true", - dest="do_execute", default=False, + make_option("-e", "--execute", + action="store_true", + dest="do_execute", + default=False, help="Execute migrations not in versions table."), - make_option("-c", "--create", action="store_true", - dest="do_create", default=False, - help="Generates sql for models that are installed but not in your database."), - make_option("--create-all", action="store_true", - dest="do_create_all", default=False, - help="Generates sql for models that are installed but not in your database."), - make_option("-s", "--seed", action="store_true", - dest="do_seed", default=False, - help="Seed nashvegas with migrations that have previously been applied in another manner."), - make_option("-d", "--database", action="append", dest="databases", + make_option("-c", "--create", + action="store_true", + dest="do_create", + default=False, + help="Generates sql for models that are installed but not " + "in your database."), + make_option("--create-all", + action="store_true", + dest="do_create_all", + default=False, + help="Generates sql for models that are installed but not " + "in your database."), + make_option("-s", "--seed", + action="store_true", + dest="do_seed", + default=False, + help="Seed nashvegas with migrations that have previously " + "been applied in another manner."), + make_option("-d", "--database", + action="append", + dest="databases", help="Nominates a database to synchronize."), - make_option("--noinput", action="store_false", dest="interactive", default=False, - help="Tells Django to NOT prompt the user for input of any kind."), + make_option("--noinput", + action="store_false", + dest="interactive", + default=False, + help="Tells Django to NOT prompt the user for input of " + "any kind."), make_option("-p", "--path", dest="path", default=None, help="The path to the database migration scripts.")) @@ -83,7 +102,9 @@ def _get_rev(self, fpath): if not rev: try: cmd = ["svn", "info", fpath] - svninfo = Popen(cmd, stdout=PIPE, stderr=PIPE).stdout.readlines() + svninfo = Popen(cmd, + stdout=PIPE, + stderr=PIPE).stdout.readlines() for info in svninfo: tokens = info.split(":") if tokens[0].strip() == "Last Changed Rev": @@ -95,14 +116,17 @@ def _get_rev(self, fpath): def _get_current_migration_number(self, database): try: - result = Migration.objects.using(database).order_by('-migration_label')[0] + result = Migration.objects.using( + database + ).order_by('-migration_label')[0] except IndexError: return 0 match = MIGRATION_NAME_RE.match(result.migration_label) return int(match.group(1)) def _get_migration_path(self, db, migration): - if db == DEFAULT_DB_ALIAS and os.path.exists(os.path.join(self.path, migration)): + default_exists = os.path.exists(os.path.join(self.path, migration)) + if db == DEFAULT_DB_ALIAS and default_exists: migration_path = os.path.join(self.path, migration) else: migration_path = os.path.join(self.path, db, migration) @@ -139,7 +163,10 @@ def _execute_migration(self, database, migration, show_traceback=True): if l.startswith("### New Model: "): created_models.add( get_model( - *l.replace("### New Model: ", "").strip().split(".") + *l.replace( + "### New Model: ", + "" + ).strip().split(".") ) ) @@ -170,8 +197,8 @@ def _execute_migration(self, database, migration, show_traceback=True): def init_nashvegas(self): # Copied from line 35 of django.core.management.commands.syncdb - # Import the 'management' module within each installed app, to register - # dispatcher events. + # Import the 'management' module within each installed app, to + # register dispatcher events. for app_name in settings.INSTALLED_APPS: try: import_module(".management", app_name) @@ -181,24 +208,27 @@ def init_nashvegas(self): # want to ignore the exception if the management module exists # but raises an ImportError for some reason. The only way we # can do this is to check the text of the exception. Note that - # we're a bit broad in how we check the text, because different - # Python implementations may not use the same text. + # we're a bit broad in how we check the text, because + # different Python implementations may not use the same text. # CPython uses the text "No module named management" # PyPy uses "No module named myproject.myapp.management" msg = exc.args[0] if not msg.startswith("No module named") or "management" not in msg: raise - # @@@ make cleaner / check explicitly for model instead of looping over and doing string comparisons + # @@@ make cleaner / check explicitly for model instead of looping + # over and doing string comparisons databases = self.databases or get_capable_databases() for database in databases: connection = connections[database] cursor = connection.cursor() all_new = get_sql_for_new_models(['nashvegas'], using=database) for lines in all_new: - to_execute = "\n".join( - [l for l in lines.split("\n") if not l.startswith("### New Model: ")] - ) + to_execute = "\n".join([ + l + for l in lines.split("\n") + if not l.startswith("### New Model: ") + ]) if not to_execute: continue cursor.execute(to_execute) @@ -216,9 +246,14 @@ def create_all_migrations(self): if not os.path.exists(db_path): os.makedirs(db_path) - path = os.path.join(db_path, '%s.sql' % (str(number + 1).zfill(4),)) + path = os.path.join( + db_path, + "%s.sql" % (str(number + 1).zfill(4),) + ) if os.path.exists(path): - raise CommandError("Unable to create %r: File already exists" % path) + raise CommandError( + "Unable to create %r: File already exists" % path + ) with open(path, 'w') as fp: for s in statements: @@ -253,8 +288,15 @@ def execute_migrations(self, show_traceback=True): migration_path = self._get_migration_path(db, migration) with Transactional(): - sys.stdout.write("Executing migration %r on %r...." % (migration, db)) - created_models = self._execute_migration(db, migration_path, show_traceback=show_traceback) + sys.stdout.write( + "Executing migration %r on %r...." % + (migration, db) + ) + created_models = self._execute_migration( + db, + migration_path, + show_traceback=show_traceback + ) emit_post_sync_signal( created_models=created_models, @@ -264,7 +306,9 @@ def execute_migrations(self, show_traceback=True): ) if self.load_initial_data: - sys.stdout.write("Running loaddata for initial_data fixtures on %r.\n" % db) + sys.stdout.write( + "Running loaddata for initial_data fixtures on %r.\n" % db + ) call_command( "loaddata", "initial_data", @@ -274,7 +318,8 @@ def execute_migrations(self, show_traceback=True): def seed_migrations(self, stop_at=None): # @@@ the command-line interface needs to be re-thinked - # TODO: this needs to be able to handle multi-db when you're specifying stop_at + # TODO: this needs to be able to handle multi-db when you're + # specifying stop_at if stop_at is None and self.args: stop_at = self.args[0] @@ -284,9 +329,13 @@ def seed_migrations(self, stop_at=None): except ValueError: raise CommandError("Invalid --seed migration") except IndexError: - raise CommandError("Usage: ./manage.py upgradedb --seed [stop_at]") + raise CommandError( + "Usage: ./manage.py upgradedb --seed [stop_at]" + ) - all_migrations = get_pending_migrations(self.path, self.databases, stop_at=stop_at) + all_migrations = get_pending_migrations( + self.path, self.databases, stop_at=stop_at + ) for db, migrations in all_migrations.iteritems(): for migration in migrations: migration_path = self._get_migration_path(db, migration) @@ -301,7 +350,9 @@ def seed_migrations(self, stop_at=None): m.save() print "%s:%s has been seeded" % (db, m.migration_label) else: - print "%s:%s was already applied" % (db, m.migration_label) + print "%s:%s was already applied" % ( + db, m.migration_label + ) def list_migrations(self): all_migrations = get_pending_migrations(self.path, self.databases) @@ -316,7 +367,9 @@ def list_migrations(self): def _get_default_migration_path(self): try: - path = os.path.dirname(os.path.normpath(os.sys.modules[settings.SETTINGS_MODULE].__file__)) + path = os.path.dirname(os.path.normpath( + os.sys.modules[settings.SETTINGS_MODULE].__file__) + ) except KeyError: path = os.getcwd() return os.path.join(path, "migrations") @@ -340,13 +393,16 @@ def handle(self, *args, **options): self.path = options.get("path") else: default_path = self._get_default_migration_path() - self.path = getattr(settings, "NASHVEGAS_MIGRATIONS_DIRECTORY", default_path) + self.path = getattr( + settings, "NASHVEGAS_MIGRATIONS_DIRECTORY", default_path + ) self.verbosity = int(options.get("verbosity", 1)) self.interactive = options.get("interactive") self.databases = options.get("databases") - # We only use the default alias in creation scenarios (upgrades default to all databases) + # We only use the default alias in creation scenarios (upgrades + # default to all databases) if self.do_create and not self.databases: self.databases = [DEFAULT_DB_ALIAS] diff --git a/nashvegas/utils.py b/nashvegas/utils.py index d7f8048..738561b 100644 --- a/nashvegas/utils.py +++ b/nashvegas/utils.py @@ -140,15 +140,15 @@ def get_file_list(path, max_depth=1, cur_depth=0): for name in os.listdir(path): if name.startswith('.'): continue - + full_path = os.path.join(path, name) if os.path.isdir(full_path): if cur_depth == max_depth: continue - - for result in get_file_list(full_path, max_depth, cur_depth + 1): + + file_list = get_file_list(full_path, max_depth, cur_depth + 1) + for result in file_list: yield result - else: yield full_path @@ -163,13 +163,15 @@ def get_applied_migrations(databases=None): else: # We only loop through databases that are listed as "capable" all_databases = list(get_capable_databases()) - databases = list(itertools.ifilter(lambda x: x in all_databases, databases)) - + databases = list( + itertools.ifilter(lambda x: x in all_databases, databases) + ) + results = defaultdict(list) for db in databases: for x in Migration.objects.using(db).order_by("migration_label"): results[db].append(x.migration_label) - + return results @@ -180,7 +182,7 @@ def get_all_migrations(path, databases=None): """ # database: [(number, full_path)] possible_migrations = defaultdict(list) - + try: in_directory = sorted(get_file_list(path)) except OSError: @@ -188,32 +190,33 @@ def get_all_migrations(path, databases=None): print "An error occurred while reading migrations from %r:" % path traceback.print_exc() return {} - - # Iterate through our results and discover which migrations are actually runnable + + # Iterate through our results and discover which migrations are + # actually runnable for full_path in in_directory: child_path, script = os.path.split(full_path) name, ext = os.path.splitext(script) - + # the database component is default if this is in the root directory # is if in a subdirectory if path == child_path: db = DEFAULT_DB_ALIAS else: db = os.path.split(child_path)[-1] - + # filter by database if set if databases and db not in databases: continue - + match = MIGRATION_NAME_RE.match(name) if match is None: raise MigrationError("Invalid migration file prefix %r " "(must begin with a number)" % name) - + number = int(match.group(1)) if ext in [".sql", ".py"]: possible_migrations[db].append((number, full_path)) - + return possible_migrations @@ -224,14 +227,14 @@ def get_pending_migrations(path, databases=None, stop_at=None): """ if stop_at is None: stop_at = float("inf") - + # database: [(number, full_path)] possible_migrations = get_all_migrations(path, databases) # database: [full_path] applied_migrations = get_applied_migrations(databases) # database: [full_path] to_execute = defaultdict(list) - + for database, scripts in possible_migrations.iteritems(): applied = applied_migrations[database] pending = to_execute[database] @@ -239,5 +242,5 @@ def get_pending_migrations(path, databases=None, stop_at=None): path, script = os.path.split(migration) if script not in applied and number <= stop_at: pending.append(script) - + return dict((k, v) for k, v in to_execute.iteritems() if v)