def do_install(config, cmd): script = alembic_script.ScriptDirectory.from_config(config) heads = script.get_revisions(script.get_heads()) status = dict() for head in heads: config.print_stdout('Upgrading {0}'.format(', '.join(head.branch_labels))) try: _install(config, head.revision, script=script) result = InstallSuccess(head) status.update(dict((label, result) for label in head.branch_labels)) except Exception as e: result = InstallFailure(head, e) status.update(dict((label, result) for label in head.branch_labels)) try: alembic_util.err(str(e)) except BaseException: # Err logs the error, but also exits pass config.print_stdout('') config.print_stdout('Summary') longest_label = len(max(status.keys(), key=len)) for label, result in sorted(status.items()): config.print_stdout('{0} {1:<8} {2}'.format( label.ljust(longest_label), result.status, result.description)) return status
def _compare_labels(revision, expected_labels): # validate that the script has expected labels only bad_labels = revision.branch_labels - expected_labels if bad_labels: # NOTE(ihrachyshka): this hack is temporary to accomodate those # projects that already initialized their branches with liberty_* # labels. Let's notify them about the deprecation for now and drop it # later. bad_labels_with_release = revision.branch_labels - _get_release_labels(expected_labels) if not bad_labels_with_release: alembic_util.warn( _( "Release aware branch labels (%s) are deprecated. " "Please switch to expand@ and contract@ " "labels." ) % bad_labels ) return script_name = os.path.basename(revision.path) alembic_util.err( _("Unexpected label for script %(script_name)s: %(labels)s") % {"script_name": script_name, "labels": bad_labels} )
def run_cmd(self, config, options): fn, positional, kwarg = options.cmd try: fn(config, *[getattr(options, k) for k in positional], **dict((k, getattr(options, k)) for k in kwarg)) except util.CommandError, e: util.err(str(e))
def _get_sorted_heads(script): '''Get the list of heads for all branches, sorted.''' heads = script.get_heads() # +1 stands for the core 'kilo' branch, the one that didn't have branches if len(heads) > len(MIGRATION_BRANCHES) + 1: alembic_util.err(_('No new branches are allowed except: %s') % ' '.join(MIGRATION_BRANCHES)) return sorted(heads)
def do_alembic_command(config, cmd, *args, **kwargs): project = config.get_main_option("neutron_project") alembic_util.msg(_("Running %(cmd)s for %(project)s ...") % {"cmd": cmd, "project": project}) try: getattr(alembic_command, cmd)(config, *args, **kwargs) except alembic_util.CommandError as e: alembic_util.err(six.text_type(e)) alembic_util.msg(_("OK"))
def update_head_file(config): script = alembic_script.ScriptDirectory.from_config(config) if len(script.get_heads()) > 1: alembic_util.err(_('Timeline branches unable to generate timeline')) head_path = os.path.join(script.versions, HEAD_FILENAME) with open(head_path, 'w+') as f: f.write(script.get_current_head())
def do_alembic_command(config, cmd, *args, **kwargs): project = config.get_main_option('neutron_project') alembic_util.msg(_('Running %(cmd)s for %(project)s ...') % {'cmd': cmd, 'project': project}) try: getattr(alembic_command, cmd)(config, *args, **kwargs) except alembic_util.CommandError as e: alembic_util.err(six.text_type(e)) alembic_util.msg(_('OK'))
def _get_sorted_heads(script): '''Get the list of heads for all branches, sorted.''' heads = script.get_heads() # +1 stands for the core 'kilo' branch, the one that didn't have branches if len(heads) > len(MIGRATION_BRANCHES) + 1: alembic_util.err( _('No new branches are allowed except: %s') % ' '.join(MIGRATION_BRANCHES)) return sorted(heads)
def _check_head(head_file, head): try: with open(head_file) as file_: observed_head = file_.read().strip() except IOError: pass else: if observed_head != head: alembic_util.err('HEAD file does not match migration timeline ' 'head, expected: %(head)s' % {'head': head})
def _get_package_root_dir(config): root_module = importutils.try_import(_get_project_base(config)) if not root_module: project = config.get_main_option('neutron_project') alembic_util.err(_("Failed to locate source for %s.") % project) # The root_module.__file__ property is a path like # '/opt/stack/networking-foo/networking_foo/__init__.py' # We return just # '/opt/stack/networking-foo' return os.path.dirname(os.path.dirname(root_module.__file__))
def _compare_labels(revision, expected_labels): # validate that the script has the only label that corresponds to path bad_labels = revision.branch_labels - expected_labels if bad_labels: script_name = os.path.basename(revision.path) alembic_util.err( _('Unexpected label for script %(script_name)s: %(labels)s') % { 'script_name': script_name, 'labels': bad_labels })
def validate_head_file(config): script = alembic_script.ScriptDirectory.from_config(config) if len(script.get_heads()) > 1: alembic_util.err(_("Timeline branches unable to generate timeline")) head_path = os.path.join(script.versions, HEAD_FILENAME) if os.path.isfile(head_path) and open(head_path).read().strip() == script.get_current_head(): return else: alembic_util.err(_("HEAD file does not match migration timeline head"))
def _compare_labels(revision, expected_labels): # validate that the script has the only label that corresponds to path bad_labels = revision.branch_labels - expected_labels if bad_labels: script_name = os.path.basename(revision.path) alembic_util.err( _('Unexpected label for script %(script_name)s: %(labels)s') % {'script_name': script_name, 'labels': bad_labels} )
def validate_head_file(config): script = alembic_script.ScriptDirectory.from_config(config) if len(script.get_heads()) > 1: alembic_util.err(_('Timeline branches unable to generate timeline')) head_path = os.path.join(script.versions, HEAD_FILENAME) if (os.path.isfile(head_path) and open(head_path).read().strip() == script.get_current_head()): return else: alembic_util.err(_('HEAD file does not match migration timeline head'))
def upgrade(ctx, migration_revision, url, delta): # TODO(mdietz): wire up delta test_connection() config = ctx.obj["alembic_config"] if not sqlalchemy_utils.database_exists(models.engine.url): alembic_util.err("Cannot continue. The database must be created with " "'create_database' first") migration_revision = migration_revision.lower() if url: config.set_main_option("sqlalchemy.url", url) _dispatch_alembic_cmd(config, "upgrade", revision=migration_revision)
def _check_head(branch_name, head_file, head): try: with open(head_file) as file_: observed_head = file_.read().strip() except IOError: pass else: if observed_head != head: alembic_util.err( _('%(branch)s HEAD file does not match migration timeline ' 'head, expected: %(head)s') % {'branch': branch_name.title(), 'head': head})
def do_alembic_command(config, cmd, *args, **kwargs): project = config.get_main_option('neutron_project') alembic_util.msg( _('Running %(cmd)s for %(project)s ...') % { 'cmd': cmd, 'project': project }) try: getattr(alembic_command, cmd)(config, *args, **kwargs) except alembic_util.CommandError as e: alembic_util.err(six.text_type(e)) alembic_util.msg(_('OK'))
def run(self, args): # let's hijack init and list_templates # we want to provide our own config object # in order to provide a custom get_template_directory function if len(args) and args[0] in ['list_templates', 'init']: config = FlaskAlembicConfig("alembic.ini") if args[0] == 'list_templates': return list_templates(config) else: try: return init(config, 'alembic', template='flask') except util.CommandError, e: util.err(str(e))
def validate_heads_file(config): """Check that HEADS file contains the latest heads for each branch.""" script = alembic_script.ScriptDirectory.from_config(config) expected_heads = _get_sorted_heads(script) heads_path = _get_active_head_file_path(config) try: with open(heads_path) as file_: observed_heads = file_.read().split() if observed_heads == expected_heads: return except IOError: pass alembic_util.err(_("HEADS file does not match migration timeline heads, expected: %s") % ", ".join(expected_heads))
def validate_revisions(config): script_dir = alembic_script.ScriptDirectory.from_config(config) revisions = _get_revisions(script_dir) for revision in revisions: _validate_revision(script_dir, revision) branchpoints = _get_branch_points(script_dir) if len(branchpoints) > 1: branchpoints = ', '.join(p.revision for p in branchpoints) alembic_util.err( _('Unexpected number of alembic branch points: %(branchpoints)s') % {'branchpoints': branchpoints})
def validate_revisions(config): script_dir = alembic_script.ScriptDirectory.from_config(config) revisions = _get_revisions(script_dir) for revision in revisions: _validate_revision(script_dir, revision) branchpoints = _get_branch_points(script_dir) if len(branchpoints) > 1: branchpoints = ', '.join(p.revision for p in branchpoints) alembic_util.err( _('Unexpected number of alembic branch points: %(branchpoints)s') % {'branchpoints': branchpoints} )
def _validate_head_file(config): script = alembic_script.ScriptDirectory.from_config(config) expected_head = script.get_heads() head_path = _get_head_file_path(config) try: with open(head_path) as file_: observed_head = file_.read().split() if observed_head == expected_head: return except IOError: pass alembic_util.err( _('HEAD file does not match migration timeline head, expected: %s') % expected_head)
def main(): config = alembic_config.Config( os.path.join(os.path.dirname(__file__), 'alembic.ini') ) config.set_main_option('script_location', 'quantum.db.migration:alembic_migrations') # attach the Quantum conf to the Alembic conf config.quantum_config = CONF cmd, args, kwargs = process_argv(sys.argv) try: getattr(alembic_command, cmd)(config, *args, **kwargs) except alembic_util.CommandError, e: alembic_util.err(str(e))
def validate_heads_file(config): '''Check that HEADS file contains the latest heads for each branch.''' script = alembic_script.ScriptDirectory.from_config(config) expected_heads = _get_sorted_heads(script) heads_path = _get_active_head_file_path(config) try: with open(heads_path) as file_: observed_heads = file_.read().split() if observed_heads == expected_heads: return except IOError: pass alembic_util.err( _('HEADS file does not match migration timeline heads, expected: %s') % ', '.join(expected_heads))
def _compare_labels(revision, expected_labels): # validate that the script has expected labels only expected_branch_labels = set() for label in revision.branch_labels: for expected_label in expected_labels: if label.endswith(expected_label): expected_branch_labels.add(label) bad_labels = revision.branch_labels - expected_branch_labels if bad_labels: script_name = os.path.basename(revision.path) alembic_util.err( _('Unexpected label for script %(script_name)s: %(labels)s') % {'script_name': script_name, 'labels': bad_labels} )
def do_alembic_command(config, cmd, revision=None, desc=None, **kwargs): args = [] if revision: args.append(revision) if desc: alembic_util.msg('Running %(cmd)s (%(desc)s)...' % { 'cmd': cmd, 'desc': desc }) else: alembic_util.msg('Running %(cmd)s ...' % {'cmd': cmd}) try: getattr(alembic_command, cmd)(config, *args, **kwargs) except alembic_util.CommandError as e: alembic_util.err(six.text_type(e)) alembic_util.msg('OK')
def do_alembic_command(config, cmd, revision=None, desc=None, **kwargs): args = [] if revision: args.append(revision) project = config.get_main_option('neutron_project') if desc: alembic_util.msg(_('Running %(cmd)s (%(desc)s) for %(project)s ...') % {'cmd': cmd, 'desc': desc, 'project': project}) else: alembic_util.msg(_('Running %(cmd)s for %(project)s ...') % {'cmd': cmd, 'project': project}) try: getattr(alembic_command, cmd)(config, *args, **kwargs) except alembic_util.CommandError as e: alembic_util.err(six.text_type(e)) alembic_util.msg(_('OK'))
def validate_head_file(config): '''Check that HEAD file contains the latest head for the branch.''' if _use_separate_migration_branches(config): return script = alembic_script.ScriptDirectory.from_config(config) expected_head = script.get_heads() head_path = _get_head_file_path(config) try: with open(head_path) as file_: observed_head = file_.read().split() if observed_head == expected_head: return except IOError: pass alembic_util.err( _('HEAD file does not match migration timeline head, expected: %s') % expected_head)
def do_alembic_command(cmd, database, *args, **kwargs): if database == 'gamecenter': folder_name = 'alembic' db_url = cfg.config().get('DB', 'sql_connection') else: raise SystemExit("database option must be one of gamecenter") configx = alembic_config.Config( os.path.join(os.path.abspath(os.path.dirname(db.__file__)), folder_name, 'alembic.ini')) configx.set_main_option('script_location', 'gamecenter.db:%s' % folder_name) configx.set_main_option('sqlalchemy.url', db_url) try: getattr(alembic_command, cmd)(configx, *args, **kwargs) except alembic_util.CommandError as e: alembic_util.err(str(e))
def do_alembic_command(config, cmd, revision=None, desc=None, **kwargs): project = config.get_main_option('neutron_project') args = [] if revision: # We use unique branch labels from Newton onwards. if revision.split('@')[0] in MIGRATION_BRANCHES: revision = '-'.join([project, revision]) args.append(revision) if desc: alembic_util.msg(_('Running %(cmd)s (%(desc)s) for %(project)s ...') % {'cmd': cmd, 'desc': desc, 'project': project}) else: alembic_util.msg(_('Running %(cmd)s for %(project)s ...') % {'cmd': cmd, 'project': project}) try: getattr(alembic_command, cmd)(config, *args, **kwargs) except alembic_util.CommandError as e: alembic_util.err(six.text_type(e)) alembic_util.msg(_('OK'))
def run(self, options, fn, positional, kwarg): from alembic.config import Config as AlembicConfig from alembic import util config = self._commandor_res alembic_cfg = AlembicConfig( os.path.join(os.path.dirname(gottwall.default_config.__file__), 'alembic.ini')) alembic_cfg.set_main_option("script_location", config['ALEMBIC_SCRIPT_LOCATION']) alembic_cfg.set_main_option("sqlalchemy.url", "{ENGINE}://{USER}:{PASSWORD}@{HOST}:{PORT}/{NAME}".\ format(**config['DATABASE'])) try: fn(alembic_cfg, *[getattr(options, k) for k in positional], **dict((k, getattr(options, k)) for k in kwarg)) except util.CommandError as e: util.err(str(e))
def run(self, options, fn, positional, kwarg): from alembic.config import Config as AlembicConfig from alembic import util config = self._commandor_res alembic_cfg = AlembicConfig(os.path.join(os.path.dirname( gottwall.default_config.__file__), 'alembic.ini')) alembic_cfg.set_main_option("script_location", config['ALEMBIC_SCRIPT_LOCATION']) alembic_cfg.set_main_option("sqlalchemy.url", "{ENGINE}://{USER}:{PASSWORD}@{HOST}:{PORT}/{NAME}".\ format(**config['DATABASE'])) try: fn(alembic_cfg, *[getattr(options, k) for k in positional], **dict((k, getattr(options, k)) for k in kwarg)) except util.CommandError, e: util.err(str(e))
def _compare_labels(revision, expected_labels): # validate that the script has expected labels only bad_labels = revision.branch_labels - expected_labels if bad_labels: # NOTE(ihrachyshka): this hack is temporary to accommodate those # projects that already initialized their branches with liberty_* # labels. Let's notify them about the deprecation for now and drop it # later. bad_labels_with_release = (revision.branch_labels - _get_release_labels(expected_labels)) if not bad_labels_with_release: alembic_util.warn( _('Release aware branch labels (%s) are deprecated. ' 'Please switch to expand@ and contract@ ' 'labels.') % bad_labels) return script_name = os.path.basename(revision.path) alembic_util.err( _('Unexpected label for script %(script_name)s: %(labels)s') % { 'script_name': script_name, 'labels': bad_labels })
def validate_head_files(config): '''Check that HEAD files contain the latest head for the branch.''' head_file = _get_head_file_path(config) heads_file = _get_heads_file_path(config) if not os.path.exists(head_file) and not os.path.exists(heads_file): alembic_util.err("Repository does not contain HEAD files") return heads = _get_heads(config) for file_ in (head_file, heads_file): if os.path.exists(file_): if not heads: alembic_util.err('HEAD file contains no head') if len(heads) > 1: alembic_util.err( 'HEAD file contains more than one head: %(heads)s' % {'heads': heads}) for head in heads: _check_head(file_, head)
def main(argv=None, prog=None, **kwargs): """The console runner function for Alembic.""" def add_options(parser, positional, kwargs): if 'template' in kwargs: parser.add_argument("-t", "--template", default='generic', type=str, help="Setup template for use with 'init'") if 'message' in kwargs: parser.add_argument("-m", "--message", type=str, help="Message string to use with 'revision'") if 'sql' in kwargs: parser.add_argument("--sql", action="store_true", help="Don't emit SQL to database - dump to " "standard output/file instead") if 'tag' in kwargs: parser.add_argument("--tag", type=str, help="Arbitrary 'tag' name - can be used by " "custom env.py scripts.") if 'autogenerate' in kwargs: parser.add_argument( "--autogenerate", action="store_true", help="Populate revision script with candidate " "migration operations, based on comparison of database to model." ) # TODO: # --dialect - name of dialect when --sql mode is set - *no DB connections # should occur, add this to env.py templates as a conditional* positional_help = { 'directory': "location of scripts directory", 'revision': "revision identifier" } for arg in positional: subparser.add_argument(arg, help=positional_help.get(arg)) parser = ArgumentParser(prog=prog) parser.add_argument("-c", "--config", type=str, default="alembic.ini", help="Alternate config file") parser.add_argument( "-n", "--name", type=str, default="alembic", help="Name of section in .ini file to use for Alembic config") subparsers = parser.add_subparsers() for fn in [getattr(command, n) for n in dir(command)]: if inspect.isfunction(fn) and \ fn.__name__[0] != '_' and \ fn.__module__ == 'alembic.command': spec = inspect.getargspec(fn) if spec[3]: positional = spec[0][1:-len(spec[3])] kwarg = spec[0][-len(spec[3]):] else: positional = spec[0][1:] kwarg = [] subparser = subparsers.add_parser(fn.__name__, help=fn.__doc__) add_options(subparser, positional, kwarg) subparser.set_defaults(cmd=(fn, positional, kwarg)) options = parser.parse_args(argv) fn, positional, kwarg = options.cmd cfg = Config(options.config, options.name) try: fn(cfg, *[getattr(options, k) for k in positional], **dict((k, getattr(options, k)) for k in kwarg)) except util.CommandError, e: util.err(str(e))
def main(argv=None, prog=None, **kwargs): """The console runner function for Alembic.""" def add_options(parser, positional, kwargs): if 'template' in kwargs: parser.add_argument("-t", "--template", default='generic', type=str, help="Setup template for use with 'init'") if 'message' in kwargs: parser.add_argument("-m", "--message", type=str, help="Message string to use with 'revision'") if 'sql' in kwargs: parser.add_argument("--sql", action="store_true", help="Don't emit SQL to database - dump to " "standard output/file instead") if 'tag' in kwargs: parser.add_argument("--tag", type=str, help="Arbitrary 'tag' name - can be used by " "custom env.py scripts.") if 'autogenerate' in kwargs: parser.add_argument("--autogenerate", action="store_true", help="Populate revision script with candidate " "migration operations, based on comparison of database to model.") # TODO: # --dialect - name of dialect when --sql mode is set - *no DB connections # should occur, add this to env.py templates as a conditional* positional_help = { 'directory':"location of scripts directory", 'revision':"revision identifier" } for arg in positional: subparser.add_argument(arg, help=positional_help.get(arg)) parser = ArgumentParser(prog=prog) parser.add_argument("-c", "--config", type=str, default="alembic.ini", help="Alternate config file") parser.add_argument("-n", "--name", type=str, default="alembic", help="Name of section in .ini file to use for Alembic config") subparsers = parser.add_subparsers() for fn in [getattr(command, n) for n in dir(command)]: if inspect.isfunction(fn) and \ fn.__name__[0] != '_' and \ fn.__module__ == 'alembic.command': spec = inspect.getargspec(fn) if spec[3]: positional = spec[0][1:-len(spec[3])] kwarg = spec[0][-len(spec[3]):] else: positional = spec[0][1:] kwarg = [] subparser = subparsers.add_parser( fn.__name__, help=fn.__doc__) add_options(subparser, positional, kwarg) subparser.set_defaults(cmd=(fn, positional, kwarg)) options = parser.parse_args(argv) fn, positional, kwarg = options.cmd cfg = Config(options.config, options.name) try: fn(cfg, *[getattr(options, k) for k in positional], **dict((k, getattr(options, k)) for k in kwarg) ) except util.CommandError, e: util.err(str(e))
def do_alembic_command(cmd, *args, **kwargs): try: getattr(alembic_command, cmd)(ALEMBIC_CONFIG, *args, **kwargs) except alembic_util.CommandError as e: alembic_util.err(str(e))
def _get_installed_entrypoint(subproject): '''Get the entrypoint for the subproject, which must be installed.''' if subproject not in migration_entrypoints: alembic_util.err(_('Package %s not installed') % subproject) return migration_entrypoints[subproject]
def _get_head_path(script): if len(script.get_heads()) > 1: alembic_util.err('Timeline branches unable to generate timeline') head_path = os.path.join(script.versions, HEAD_FILENAME) return head_path
def do_alembic_command(config, cmd, *args, **kwargs): try: getattr(alembic_cmd, cmd)(config, *args, **kwargs) except alembic_u.CommandError as e: alembic_u.err(six.text_type(e))
def validate_cli_options(): if CONF.subproject and CONF.service: alembic_util.err(_("Cannot specify both --service and --subproject."))
def _get_alembic_entrypoint(project): if project not in migration_entrypoints: alembic_util.err(_('Sub-project %s not installed.') % project) return migration_entrypoints[project]
def run(self, cmd, config, *args, **kwargs): from alembic import command, util try: getattr(command, cmd)(config, *args, **kwargs) except util.CommandError, e: util.err(str(e))
def validate_service_installed(service): if not importutils.try_import('neutron_%s' % service): alembic_util.err(_('Package neutron-%s not installed') % service)
def do_alembic_command(config, cmd, *args, **kwargs): try: getattr(alembic_command, cmd)(config, *args, **kwargs) except alembic_util.CommandError as e: alembic_util.err(str(e))